KL-Py 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.
- KL_Py/KL_Py.py +4400 -0
- KL_Py/__init__.py +1 -0
- KL_Py/hindGui/__init__.py +16529 -0
- KL_Py/hindGui/_utils.py +140 -0
- KL_Py/hindGui/elements/base.py +1055 -0
- KL_Py/hindGui/elements/button.py +947 -0
- KL_Py/hindGui/elements/calendar.py +222 -0
- KL_Py/hindGui/elements/canvas.py +122 -0
- KL_Py/hindGui/elements/center.py +44 -0
- KL_Py/hindGui/elements/checkbox.py +240 -0
- KL_Py/hindGui/elements/column.py +443 -0
- KL_Py/hindGui/elements/combo.py +329 -0
- KL_Py/hindGui/elements/error.py +47 -0
- KL_Py/hindGui/elements/frame.py +273 -0
- KL_Py/hindGui/elements/graph.py +817 -0
- KL_Py/hindGui/elements/helpers.py +202 -0
- KL_Py/hindGui/elements/image.py +324 -0
- KL_Py/hindGui/elements/input.py +310 -0
- KL_Py/hindGui/elements/list_box.py +392 -0
- KL_Py/hindGui/elements/menu.py +192 -0
- KL_Py/hindGui/elements/multiline.py +685 -0
- KL_Py/hindGui/elements/option_menu.py +168 -0
- KL_Py/hindGui/elements/pane.py +127 -0
- KL_Py/hindGui/elements/progress_bar.py +304 -0
- KL_Py/hindGui/elements/radio.py +252 -0
- KL_Py/hindGui/elements/separator.py +64 -0
- KL_Py/hindGui/elements/sizegrip.py +34 -0
- KL_Py/hindGui/elements/slider.py +199 -0
- KL_Py/hindGui/elements/spin.py +252 -0
- KL_Py/hindGui/elements/status_bar.py +165 -0
- KL_Py/hindGui/elements/stretch.py +26 -0
- KL_Py/hindGui/elements/tab.py +697 -0
- KL_Py/hindGui/elements/table.py +463 -0
- KL_Py/hindGui/elements/text.py +413 -0
- KL_Py/hindGui/elements/tree.py +493 -0
- KL_Py/hindGui/replace.py +45 -0
- KL_Py/hindGui/tray.py +358 -0
- KL_Py/hindGui/window.py +2906 -0
- KL_Py/requests/__init__.py +184 -0
- KL_Py/requests/__version__.py +14 -0
- KL_Py/requests/_internal_utils.py +50 -0
- KL_Py/requests/adapters.py +719 -0
- KL_Py/requests/api.py +157 -0
- KL_Py/requests/auth.py +314 -0
- KL_Py/requests/certifi/__init__.py +4 -0
- KL_Py/requests/certifi/__main__.py +12 -0
- KL_Py/requests/certifi/core.py +83 -0
- KL_Py/requests/certifi/py.typed +0 -0
- KL_Py/requests/certs.py +17 -0
- KL_Py/requests/charset_normalizer/__init__.py +48 -0
- KL_Py/requests/charset_normalizer/__main__.py +6 -0
- KL_Py/requests/charset_normalizer/api.py +671 -0
- KL_Py/requests/charset_normalizer/cd.py +421 -0
- KL_Py/requests/charset_normalizer/cli/__init__.py +8 -0
- KL_Py/requests/charset_normalizer/cli/__main__.py +363 -0
- KL_Py/requests/charset_normalizer/constant.py +2031 -0
- KL_Py/requests/charset_normalizer/legacy.py +80 -0
- KL_Py/requests/charset_normalizer/md.py +744 -0
- KL_Py/requests/charset_normalizer/models.py +359 -0
- KL_Py/requests/charset_normalizer/py.typed +0 -0
- KL_Py/requests/charset_normalizer/utils.py +420 -0
- KL_Py/requests/charset_normalizer/version.py +8 -0
- KL_Py/requests/compat.py +106 -0
- KL_Py/requests/cookies.py +561 -0
- KL_Py/requests/exceptions.py +151 -0
- KL_Py/requests/help.py +134 -0
- KL_Py/requests/hooks.py +33 -0
- KL_Py/requests/idna/__init__.py +45 -0
- KL_Py/requests/idna/codec.py +122 -0
- KL_Py/requests/idna/compat.py +15 -0
- KL_Py/requests/idna/core.py +437 -0
- KL_Py/requests/idna/idnadata.py +4309 -0
- KL_Py/requests/idna/intranges.py +57 -0
- KL_Py/requests/idna/package_data.py +1 -0
- KL_Py/requests/idna/py.typed +0 -0
- KL_Py/requests/idna/uts46data.py +8841 -0
- KL_Py/requests/models.py +1039 -0
- KL_Py/requests/packages.py +23 -0
- KL_Py/requests/sessions.py +831 -0
- KL_Py/requests/status_codes.py +128 -0
- KL_Py/requests/structures.py +99 -0
- KL_Py/requests/urllib3/__init__.py +211 -0
- KL_Py/requests/urllib3/_base_connection.py +165 -0
- KL_Py/requests/urllib3/_collections.py +487 -0
- KL_Py/requests/urllib3/_request_methods.py +278 -0
- KL_Py/requests/urllib3/_version.py +34 -0
- KL_Py/requests/urllib3/connection.py +1099 -0
- KL_Py/requests/urllib3/connectionpool.py +1178 -0
- KL_Py/requests/urllib3/contrib/__init__.py +0 -0
- KL_Py/requests/urllib3/contrib/emscripten/__init__.py +17 -0
- KL_Py/requests/urllib3/contrib/emscripten/connection.py +260 -0
- KL_Py/requests/urllib3/contrib/emscripten/fetch.py +726 -0
- KL_Py/requests/urllib3/contrib/emscripten/request.py +22 -0
- KL_Py/requests/urllib3/contrib/emscripten/response.py +277 -0
- KL_Py/requests/urllib3/contrib/pyopenssl.py +564 -0
- KL_Py/requests/urllib3/contrib/socks.py +228 -0
- KL_Py/requests/urllib3/exceptions.py +335 -0
- KL_Py/requests/urllib3/fields.py +341 -0
- KL_Py/requests/urllib3/filepost.py +89 -0
- KL_Py/requests/urllib3/http2/__init__.py +53 -0
- KL_Py/requests/urllib3/http2/connection.py +356 -0
- KL_Py/requests/urllib3/http2/probe.py +87 -0
- KL_Py/requests/urllib3/poolmanager.py +651 -0
- KL_Py/requests/urllib3/py.typed +2 -0
- KL_Py/requests/urllib3/response.py +1480 -0
- KL_Py/requests/urllib3/util/__init__.py +42 -0
- KL_Py/requests/urllib3/util/connection.py +137 -0
- KL_Py/requests/urllib3/util/proxy.py +43 -0
- KL_Py/requests/urllib3/util/request.py +263 -0
- KL_Py/requests/urllib3/util/response.py +101 -0
- KL_Py/requests/urllib3/util/retry.py +549 -0
- KL_Py/requests/urllib3/util/ssl_.py +527 -0
- KL_Py/requests/urllib3/util/ssl_match_hostname.py +159 -0
- KL_Py/requests/urllib3/util/ssltransport.py +271 -0
- KL_Py/requests/urllib3/util/timeout.py +275 -0
- KL_Py/requests/urllib3/util/url.py +469 -0
- KL_Py/requests/urllib3/util/util.py +42 -0
- KL_Py/requests/urllib3/util/wait.py +124 -0
- KL_Py/requests/utils.py +1086 -0
- KL_Py/when.py +144 -0
- kl_py-0.0.1.dist-info/METADATA +15 -0
- kl_py-0.0.1.dist-info/RECORD +125 -0
- kl_py-0.0.1.dist-info/WHEEL +5 -0
- kl_py-0.0.1.dist-info/licenses/LICENSE +21 -0
- kl_py-0.0.1.dist-info/top_level.txt +1 -0
KL_Py/KL_Py.py
ADDED
|
@@ -0,0 +1,4400 @@
|
|
|
1
|
+
from types import *
|
|
2
|
+
from typing import Callable, TypeVar, NewType, Any, Optional, Union, get_origin, Final, Self, Generic, Sequence, Iterable, Iterator, Generator, Mapping, List, Tuple, Set, Dict, defaultdict, Counter, Literal, NoReturn, Never
|
|
3
|
+
from abc import abstractmethod, ABCMeta, ABC as AbstractBaseClass
|
|
4
|
+
import functools
|
|
5
|
+
from functools import reduce, lru_cache, cache, wraps, partial, partialmethod
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
# need both math imports for convenience
|
|
8
|
+
from numbers import Number
|
|
9
|
+
from random import randint as old_randint, uniform as old_randflt
|
|
10
|
+
import time
|
|
11
|
+
import time as timer
|
|
12
|
+
from threading import Timer
|
|
13
|
+
import datetime
|
|
14
|
+
from dateutil.parser import parse as parse_date, ParserError
|
|
15
|
+
from math import *
|
|
16
|
+
# need both math imports for convenience
|
|
17
|
+
from copy import deepcopy
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
import builtins, os, sys, argparse, io, asyncio, random, urllib, traceback, time as Time, platform, json, shutil, glob, shlex, signal, site, base64, enum, collections, collections.abc, importlib, functools, cmd, ctypes, stat, math, re, ast, webbrowser, subprocess, requests
|
|
20
|
+
from base64 import b64encode, b64decode
|
|
21
|
+
from urllib.parse import quote_plus as encode_url, quote as encode_url_soft, unquote_plus as normalize_url, unquote as normalize_url_soft
|
|
22
|
+
from contextlib import contextmanager, redirect_stdout, redirect_stderr
|
|
23
|
+
from itertools import product as collective_iter, count
|
|
24
|
+
from re import escape
|
|
25
|
+
import enum # NOTE: to allow enum.auto without making it global
|
|
26
|
+
# both of these imports are needed ^V
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from inspect import *
|
|
29
|
+
from hindGui import *
|
|
30
|
+
from when import *
|
|
31
|
+
encodeurl = urlencode = url_encode = encode_url
|
|
32
|
+
encodeurlsoft = encode_urlsoft = urlencodesoft = url_encode_soft =encode_url_soft
|
|
33
|
+
decodeurl = decode_url = normurl = norm_url = normalizeurl = urldecode = url_decode =normalize_url
|
|
34
|
+
decodeurlsoft = decode_url_soft = normurlsoft = norm_url_soft = normalizeurlsoft = urlencodesoft = url_encode_soft =normalize_url_soft
|
|
35
|
+
base64.encode = base64_encode = base64.b64encode
|
|
36
|
+
base64.decode = base64_decode = base64.b64decode
|
|
37
|
+
Many = Union
|
|
38
|
+
Nullable = Optional
|
|
39
|
+
argv = ARGV = sys.argv[1:]
|
|
40
|
+
# helper regexes
|
|
41
|
+
HEX_RE = HEX_REGEX = r"(?:0x|#)?(?:[a-f0-9]{3}){1,2}"
|
|
42
|
+
PIN_RE = PIN_REGEX = r"^\d{4,64}$"
|
|
43
|
+
MAIL_RE = MAIL_REGEX = EMAIL_RE = EMAIL_REGEX = r"(?P<profile>[\w.+\!\-]+)@(?P<domain>[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)(?P<suffix>(?:\.[a-zA-Z]{2,})+)"
|
|
44
|
+
STRICT_PWD_RE = STRICT_PWD_REGEX = STRICT_PASSWORD_RE = STRICT_PASSWORD_REGEX = r"(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\d ])(.{8,})"
|
|
45
|
+
PHONE_RE = PHONE_REGEX = r"(?:(?P<start>\+|0{2})?(?P<country>\d{1,3}))?(?:[\-\(]|(?<=\d) )*(?P<A>\d{3})[ \-\)]*(?P<B>\d{3})[ \-\)]*(?P<C>\d{4})"
|
|
46
|
+
HTML_RE = HTML_REGEX = r"\s*(?P<tag>\<\s*(?P<tagName>[\!\/]?\w+)\s*(?P<attributes>(?P<attributeName>[\w\-]+)(?:\s*\=\s*[\"\']?(?P<attributeValue>[^\"\'\<\>]+)?[\"\']?\s*)?\s*)*\s*\/?>)(?P<content>[^\<\>]*)(?P<possibleClosingTag>\<\s*\/\s*(?P<possibleClosingTagName>\w+)\s*\>)?\s*"
|
|
47
|
+
CSS_RE = CSS_REGEX = r"(?P<tag>[\w.\#\:\-\s\,\+\~\>\[\]\=\'\"\\\^\$\~\*]+)\s*\{(?P<pairs>(?:\s*[\w\-]{3,}\:\s*[\w\s\-\,\(\)\\\'\"\#\%.\+\-\*\/]+;\s*)+)\}"
|
|
48
|
+
URL_RE = URL_REGEX = r"(?P<protocol>\w+\:[\\\/]{2,3})?(?:(?P<subDomain>[\w\-]+)\.)?(?P<domain>[\w\-]+)(?P<suffix>(?:\.[a-zA-Z]{2,})+)(?P<port>\:\d{1,5})?(?P<route>\/[^ \?\=\&\#]*)?(?P<query>\?[^ \#]*)?(?P<hash>\#[\w\-]*)?"
|
|
49
|
+
TITLE_CASED_WORD_RE = TITLE_CASED_WORD_REGEX = r"[A-Z][a-z]*(?: +[A-Z][a-z]*)+"
|
|
50
|
+
ALPHA_RE = ALPHA_REGEX = r"[A-Za-z]+"
|
|
51
|
+
LETTERS_WITH_SYMBOLS_RE = LETTERS_WITH_SYMBOLS_REGEX = r"[a-zA-Z (\(\)\{\}\[\]\&\:\;\-\'\"\?\!\,\.)]+"
|
|
52
|
+
TRAILING_SPACE_RE = TRAILING_SPACE_REGEX = r"(^\s+|\s+$)"
|
|
53
|
+
NUM_RE = NUM_REGEX = r"(\-?\d*\.?\d+)"
|
|
54
|
+
NON_NUM_RE: str = r"[^\-\.\d]+"
|
|
55
|
+
INT_RE = INTEGEGER_RE = INT_REGEX = INTEGEGER_REGEX = r"\-?\d+"
|
|
56
|
+
WORD_RE = WORD_REGEX = r"[A-Za-z_\'][\w\']*(?:\-[A-Za-z_\']\w*(?: [A-Za-z_\'][\w\']*){0})*"
|
|
57
|
+
NON_WORD_RE = NON_WORD_REGEX = r"[^A-Za-z_\-]|\-(?![A-Za-z_])"
|
|
58
|
+
def __rgx_is_full_match__(pattern, s): return bool(re.search(f"^{pattern}$", str(s) if s is not None else ""))
|
|
59
|
+
def __rgx_catch__(pattern, s) -> str | list[str]:
|
|
60
|
+
matches: list[str] = re.findall(pattern, str(s) if s is not None else "")
|
|
61
|
+
return matches[0] if len(matches) == 1 else matches
|
|
62
|
+
jumle_me_he = lafz_me_he = lambda y, x: re.search(y, x) or False if isinstance(y, str) and isinstance(x, str) else False
|
|
63
|
+
is_mail = is_email = ismail = isemail = lambda s: __rgx_is_full_match__(MAIL_RE, s)
|
|
64
|
+
he_mail = hemail = he_email = heemail = is_mail
|
|
65
|
+
catch_mail = catch_email = catchmail = catchemail = pakro_mail = pakromail = pakro_email = pakroemail = lambda s: __rgx_catch__(MAIL_RE, s)
|
|
66
|
+
has_mail = has_email = hasmail = hasemail = lambda s: catch_mail(s) != []
|
|
67
|
+
me_he_mail = mehemail = me_he_email = meheemail = has_mail
|
|
68
|
+
is_strict_pwd = is_strictpwd = isstrict_pwd = isstrictpwd = lambda s: __rgx_is_full_match__(STRICT_PWD_RE, s)
|
|
69
|
+
he_strict_pwd = he_strictpwd = hestrict_pwd = hestrictpwd = is_strict_pwd
|
|
70
|
+
catch_strict_pwd = catch_strictpwd = catchstrict_pwd = catchstrictpwd = pakro_strict_pwd = pakro_strictpwd = pakrostrict_pwd = pakrostrictpwd = lambda s: __rgx_catch__(STRICT_PWD_RE, s)
|
|
71
|
+
has_strict_pwd = has_strictpwd = hasstrict_pwd = hasstrictpwd = lambda s: catch_strict_pwd(s) != []
|
|
72
|
+
is_phone = isphone = is_phone_number = isphonenumber = is_phone_nr = isphonenr = lambda s: __rgx_is_full_match__(PHONE_RE, s)
|
|
73
|
+
he_phone = hephone = he_phone_number = hephonenumber = he_phone_nr = hephonenr = is_phone
|
|
74
|
+
catch_phone = catchphone = catch_phone_number = catchphonenumber = catch_phone_nr = catchphonenr = lambda s: __rgx_catch__(PHONE_RE, s)
|
|
75
|
+
pakro_phone = pakrophone = pakro_phone_number = pakrophonenumber = pakro_phone_nr = pakrophonenr = catch_phone
|
|
76
|
+
has_phone = hasphone = has_phone_nr = hasphonenr = has_phone_number = hasphonenumber = lambda s: catch_phone(s) != []
|
|
77
|
+
me_he_phone = mehephone = me_he_phone_nr = mehephonenr = me_he_phone_number = mehephonenumber = has_phone
|
|
78
|
+
is_html = ishtml = he_html = hehtml = lambda s: __rgx_is_full_match__(HTML_RE, s)
|
|
79
|
+
catch_html = catchhtml = pakro_html = pakrohtml = lambda s: __rgx_catch__(HTML_RE, s)
|
|
80
|
+
has_html = hashtml = me_he_html = mehehtml = lambda s: catch_html(s) != []
|
|
81
|
+
is_css = iscss = he_css = hecss = lambda s: __rgx_is_full_match__(CSS_RE, s)
|
|
82
|
+
catch_css = catchcss = lambda s: __rgx_catch__(CSS_RE, s)
|
|
83
|
+
has_css = hascss = lambda s: catch_css(s) != []
|
|
84
|
+
is_url = isurl = he_url = heurl = lambda s: __rgx_is_full_match__(URL_RE, s)
|
|
85
|
+
catch_url = catchurl = pakro_url = pakrourl = lambda s: __rgx_catch__(URL_RE, s)
|
|
86
|
+
has_url = hasurl = me_he_url = mehe_url = meheurl = lambda s: catch_url(s) != []
|
|
87
|
+
is_title_cased_word = is_titlecasedword = lambda s: __rgx_is_full_match__(TITLE_CASED_WORD_RE, s)
|
|
88
|
+
catch_title_cased_word = catchtitle_cased_word = lambda s: __rgx_catch__(TITLE_CASED_WORD_RE, s)
|
|
89
|
+
has_title_cased_word = hastitle_cased_word = lambda s: catch_title_cased_word(s) != []
|
|
90
|
+
is_alpha = isalpha = is_letter = isletter = lambda s: __rgx_is_full_match__(ALPHA_RE, s)
|
|
91
|
+
catch_alpha = catchalpha = catch_letter = catchletter = lambda s: __rgx_catch__(ALPHA_RE, s)
|
|
92
|
+
has_alpha = hasalpha = has_letter = hasletter = lambda s: catch_alpha(s) != []
|
|
93
|
+
is_num_like = isnumlike = he_num_jesa = henumjesa = he_num_jesi = henumjesi = he_parsable_num = heparsablenum = lambda s: __rgx_is_full_match__(NUM_RE, s)
|
|
94
|
+
catch_num = catchnum = pakro_num = pakronum = lambda s: __rgx_catch__(NUM_RE, s)
|
|
95
|
+
has_num = hasnum = me_he_num = mehenum = lambda s: catch_num(s) != []
|
|
96
|
+
catch_non_num = catchnonnum = pakro_non_num = pakrononnum = lambda s: __rgx_catch__(NON_NUM_RE, s)
|
|
97
|
+
has_non_num = hasnonnum = me_he_non_num = mehenonnum = lambda s: catch_non_num(s) != []
|
|
98
|
+
catch_int = catchint = lambda s: __rgx_catch__(INT_RE, s)
|
|
99
|
+
has_int = hasint = ne_he_int = meheint = lambda s: catch_int(s) != []
|
|
100
|
+
is_word = isword = lambda s: __rgx_is_full_match__(WORD_RE, s)
|
|
101
|
+
catch_word = catchword = pakro_word = pakroword = lambda s: __rgx_catch__(WORD_RE, s)
|
|
102
|
+
has_word = hasword = lambda s: catch_word(s) != []
|
|
103
|
+
is_non_word = isnon_word = isnonword = he_non_word = henon_word = henonword = lambda s: __rgx_is_full_match__(NON_WORD_RE, s)
|
|
104
|
+
catch_non_word = catchnon_word = catchnonword = pakro_non_word = pakronon_word = pakrononword = lambda s: __rgx_catch__(NON_WORD_RE, s)
|
|
105
|
+
has_non_word = hasnonword = me_he_non_word = mehenonword = lambda s: catch_non_word(s) != []
|
|
106
|
+
is_hex = ishex = he_hex = hehex = lambda s: __rgx_is_full_match__(HEX_RE, s)
|
|
107
|
+
catch_hex = catchhex = pakro_hex = pakrohex = lambda s: __rgx_catch__(HEX_RE, s)
|
|
108
|
+
has_hex = hashex = me_he_hex = mehehex = lambda s: catch_hex(s) != []
|
|
109
|
+
is_pin = ispin = he_pin = hepin = lambda s: __rgx_is_full_match__(PIN_RE, s)
|
|
110
|
+
catch_pin = catchpin = pakro_pin = pakropin = lambda s: __rgx_catch__(PIN_RE, s)
|
|
111
|
+
has_pin = haspin = me_he_pin = mehepin = lambda s: catch_pin(s) != []
|
|
112
|
+
|
|
113
|
+
# file function aliases
|
|
114
|
+
def make_file(filename: str, content: str = "") -> None:
|
|
115
|
+
if not isinstance(filename, str) or not filename.strip():
|
|
116
|
+
return
|
|
117
|
+
if not isinstance(content, str):
|
|
118
|
+
content = ""
|
|
119
|
+
with open(filename, mode="w", encoding="utf-8") as f:
|
|
120
|
+
f.write(content)
|
|
121
|
+
os.make_file = os.touch = make_file
|
|
122
|
+
os.make_folder = os.create_folder = os.touch_folder = lambda folder_path: os.makedirs(folder_path, exist_ok=True) if isinstance(folder_path, str) and folder_path.strip() else None
|
|
123
|
+
os.copy_file = os.copy = shutil.copy_file = lambda filename, dest: shutil.copy2(filename, dest) if all([isinstance(filename, str), str(filename).strip(), isinstance(dest, str), str(dest).strip()]) else None
|
|
124
|
+
os.move = lambda filename, dest: os.replace(filename, dest) if all([isinstance(filename, str), str(filename).strip(), isinstance(dest, str), str(dest).strip()]) else None
|
|
125
|
+
os.delete_file = os.remove_file = lambda filename: os.remove(filename) if isinstance(filename, str) and filename.strip() else None
|
|
126
|
+
os.remove_folder = os.delete_folder = shutil.remove_folder = shutil.delete_folder = lambda folder_path: shutil.rmtree(folder_path) if isinstance(folder_path, str) and folder_path.strip() else None
|
|
127
|
+
def saare(*args, default=None, n: int | float = 1) -> Any:
|
|
128
|
+
if len(args) >= 1 and isinstance(args[0], (list, tuple, float)):
|
|
129
|
+
if len(args) == 2:
|
|
130
|
+
args, default = [*args]
|
|
131
|
+
elif len(args) == 3:
|
|
132
|
+
args, default, n = [*args]
|
|
133
|
+
else:
|
|
134
|
+
args = args[0]
|
|
135
|
+
if not len(args):
|
|
136
|
+
return default
|
|
137
|
+
if isinstance(n, float):
|
|
138
|
+
n = int(n)
|
|
139
|
+
if type(n) not in (type(None), int):
|
|
140
|
+
n = None
|
|
141
|
+
if isinstance(args, (tuple, set)):
|
|
142
|
+
args = list(args)
|
|
143
|
+
if all(args):
|
|
144
|
+
truthies: list = [arg for arg in args if arg]
|
|
145
|
+
if isinstance(n, int) and n == 1 and len(truthies) >= 1:
|
|
146
|
+
return truthies[-1]
|
|
147
|
+
elif isinstance(n, int) and n >= 2:
|
|
148
|
+
try:
|
|
149
|
+
return truthies[:int(n) if isinstance(n, (int, float)) and 0<=n<=len(args) else len(args)]
|
|
150
|
+
except IndexError:
|
|
151
|
+
...
|
|
152
|
+
return truthies
|
|
153
|
+
return default
|
|
154
|
+
sab = both = sare = saare
|
|
155
|
+
def either(*args, default=None, n: int | float = 1) -> Any:
|
|
156
|
+
if len(args) >= 1 and isinstance(args[0], (list, tuple, float)):
|
|
157
|
+
if len(args) == 2:
|
|
158
|
+
args, default = [*args]
|
|
159
|
+
elif len(args) == 3:
|
|
160
|
+
args, default, n = [*args]
|
|
161
|
+
else:
|
|
162
|
+
args = args[0]
|
|
163
|
+
if not len(args):
|
|
164
|
+
return default
|
|
165
|
+
if isinstance(n, float):
|
|
166
|
+
n = int(n)
|
|
167
|
+
if type(n) not in (type(None), int):
|
|
168
|
+
n = None
|
|
169
|
+
if isinstance(args, (tuple, set)):
|
|
170
|
+
args = list(args)
|
|
171
|
+
if any(args):
|
|
172
|
+
truthies: list = [arg for arg in args if arg]
|
|
173
|
+
if isinstance(n, int) and n == 1 and len(truthies) >= 1:
|
|
174
|
+
return truthies[0]
|
|
175
|
+
elif isinstance(n, int) and n >= 2:
|
|
176
|
+
try:
|
|
177
|
+
return truthies[:int(n) if isinstance(n, (int, float)) and 0<=n<=len(args) else len(args)]
|
|
178
|
+
except IndexError:
|
|
179
|
+
...
|
|
180
|
+
return truthies
|
|
181
|
+
return default
|
|
182
|
+
yato = ya_to = kuch = some = chand = either
|
|
183
|
+
def neither(*args, default=[], n: int | float | None = None) -> Any:
|
|
184
|
+
if len(args) >= 1 and isinstance(args[0], (list, tuple, float)):
|
|
185
|
+
if len(args) == 2:
|
|
186
|
+
args, default = [*args]
|
|
187
|
+
elif len(args) == 3:
|
|
188
|
+
args, default, n = [*args]
|
|
189
|
+
else:
|
|
190
|
+
args = args[0]
|
|
191
|
+
if not len(args):
|
|
192
|
+
return default
|
|
193
|
+
if isinstance(n, float):
|
|
194
|
+
n = int(n)
|
|
195
|
+
if type(n) not in (type(None), int):
|
|
196
|
+
n = None
|
|
197
|
+
if isinstance(args, (tuple, set)):
|
|
198
|
+
args = list(args)
|
|
199
|
+
if not any(args):
|
|
200
|
+
try:
|
|
201
|
+
return [arg for arg in args if not arg][:int(n) if isinstance(n, int) and 0<=n<=len(args) else len(args)]
|
|
202
|
+
except IndexError:
|
|
203
|
+
return args
|
|
204
|
+
return default
|
|
205
|
+
nahi = nato = na_to = neither
|
|
206
|
+
def xor(*args: tuple[Any]) -> bool:
|
|
207
|
+
return sum(map(bool, args)) == 1
|
|
208
|
+
# helper placeholders
|
|
209
|
+
OR = YA = NOR = AND = AUR = 0
|
|
210
|
+
EXCL = EXCL_END = EXCL_STOP = EXCLUSIVE = EXCLUSIVE_STOP = EXCLUSIVE_END = EXCLUSIVE_LAST = BAGER = BAGERAKHRI = BAGER_AKHRI = 0
|
|
211
|
+
INCL = INCL_END = INCL_STOP = INCLUSIVE = INCLUSIVE_STOP = INCLUSIVE_END = INCLUSIVE_LAST = SHAMIL = SHAAMIL = SHAMIL_AKHRI = SHAAMIL_AKHRI = 1
|
|
212
|
+
FINCL = FINCL_END = FINCL_STOP = FORCE_INCLUSIVE = FORCE_INCLUSIVE_STOP = FORCE_INCLUSIVE_END = FORCE_INCLUSIVE_LAST = ZABARDASTI_SHAMIL = ZABARDASTI_SHAAMIL = ZABARDASTI_SHAMIL_AKHRI = ZABARDASTI_SHAAMIL_AKHRI = 2
|
|
213
|
+
NO_REVERSE = NON_REVERSE = NOT_REVERSE = DO_NOT_REVERSE = DONT_REVERSE = NO_REVERT = NON_REVERT = NOT_REVERT = DO_NOT_REVERT = DONT_REVERT = NAHI_REVERSE = NAHI_REVERSED = NAHI_REVERT = NOT_REVERSE = NOT_REVERSED = NAHI_ULTA = NAHI_ULTI = NAHI_ULTE = NAHI_ULAT = 0
|
|
214
|
+
ULAT = ULTA = ULTI = ULTE = REVERSE = REVERT = REVERSED = 1
|
|
215
|
+
def _map(array: list | tuple | set, x: Callable, if_: Callable = lambda _: 1) -> list:
|
|
216
|
+
if type(x) not in (Callable, type):
|
|
217
|
+
return array
|
|
218
|
+
was_a_tuple: bool = False
|
|
219
|
+
was_a_set: bool = False
|
|
220
|
+
if type(array) == tuple:
|
|
221
|
+
array = list(array)
|
|
222
|
+
was_a_tuple = True
|
|
223
|
+
if type(array) == set:
|
|
224
|
+
array = list(array)
|
|
225
|
+
was_a_set = True
|
|
226
|
+
if type(array) != list:
|
|
227
|
+
return []
|
|
228
|
+
result = []
|
|
229
|
+
try:
|
|
230
|
+
result = [x(v) for v in array if callable(if_) and if_(v)]
|
|
231
|
+
except (TypeError, ValueError):
|
|
232
|
+
pass
|
|
233
|
+
if was_a_tuple:
|
|
234
|
+
result = tuple(result)
|
|
235
|
+
if was_a_set:
|
|
236
|
+
result = set(result)
|
|
237
|
+
return result
|
|
238
|
+
def pehla(iterable: Iterable) -> Any:
|
|
239
|
+
if not isinstance(iterable, Iterable)\
|
|
240
|
+
or not len(iterable):
|
|
241
|
+
return
|
|
242
|
+
try:
|
|
243
|
+
return iterable[0]
|
|
244
|
+
except IndexError:
|
|
245
|
+
...
|
|
246
|
+
def dusra(iterable: Iterable) -> Any:
|
|
247
|
+
if not isinstance(iterable, Iterable)\
|
|
248
|
+
or len(iterable) < 1:
|
|
249
|
+
return
|
|
250
|
+
try:
|
|
251
|
+
return iterable[1]
|
|
252
|
+
except IndexError:
|
|
253
|
+
...
|
|
254
|
+
def tisra(iterable: Iterable) -> Any:
|
|
255
|
+
if not isinstance(iterable, Iterable)\
|
|
256
|
+
or len(iterable) < 2:
|
|
257
|
+
return
|
|
258
|
+
try:
|
|
259
|
+
return iterable[2]
|
|
260
|
+
except IndexError:
|
|
261
|
+
...
|
|
262
|
+
teesra = tisra
|
|
263
|
+
def tisra_akhri(iterable: Iterable) -> Any:
|
|
264
|
+
if not isinstance(iterable, Iterable)\
|
|
265
|
+
or len(iterable) < 2:
|
|
266
|
+
return
|
|
267
|
+
try:
|
|
268
|
+
return iterable[-3]
|
|
269
|
+
except IndexError:
|
|
270
|
+
...
|
|
271
|
+
teesra_aakhri = teesra_akhri = tisra_aakhri = tisra_akhri
|
|
272
|
+
def dusra_akhri(iterable: Iterable) -> Any:
|
|
273
|
+
if not isinstance(iterable, Iterable)\
|
|
274
|
+
or len(iterable) < 1:
|
|
275
|
+
return
|
|
276
|
+
try:
|
|
277
|
+
return iterable[-2]
|
|
278
|
+
except IndexError:
|
|
279
|
+
...
|
|
280
|
+
dusra_aakhri = dusra_akhri
|
|
281
|
+
def akhri(iterable: Iterable) -> Any:
|
|
282
|
+
if not isinstance(iterable, Iterable)\
|
|
283
|
+
or not len(iterable):
|
|
284
|
+
return
|
|
285
|
+
try:
|
|
286
|
+
return iterable[-1]
|
|
287
|
+
except IndexError:
|
|
288
|
+
...
|
|
289
|
+
aakhri = akhri
|
|
290
|
+
# ATTENTION: No changes to the following function (EVER):
|
|
291
|
+
__old_open__ = builtins.open
|
|
292
|
+
def open(file, mode="r", buffering=-1, encoding=None, *args, **kwargs):
|
|
293
|
+
if isinstance(mode, str) and "b" not in mode.lower():
|
|
294
|
+
encoding = "utf-8"
|
|
295
|
+
return __old_open__(file, mode=mode, buffering=buffering, encoding=encoding, *args, **kwargs)
|
|
296
|
+
builtins.open = open
|
|
297
|
+
# could help make IO a little easier to work with
|
|
298
|
+
# so no more encoding="..." everywhere
|
|
299
|
+
# CATCH: the mode has to stay any of the following non-binary modes:
|
|
300
|
+
# ['w', 'r', 'a', 'w+', 'r+', 'a+']
|
|
301
|
+
# as the original builtins.open does not allow encoding
|
|
302
|
+
# with binary mode
|
|
303
|
+
# ^
|
|
304
|
+
# WARNING
|
|
305
|
+
# NO CHANGED PLEASE!
|
|
306
|
+
# THIS CAN RUIN THE ENTIRE ENVIROMENT
|
|
307
|
+
def try_else(x: Any, y: Any) -> Any|None:
|
|
308
|
+
try:
|
|
309
|
+
if not x:
|
|
310
|
+
raise Exception()
|
|
311
|
+
# if x does not even exist
|
|
312
|
+
# to begin with,
|
|
313
|
+
# let's just skip to the except block right away
|
|
314
|
+
if callable(x):
|
|
315
|
+
x = x()
|
|
316
|
+
# if callable,
|
|
317
|
+
# replace x with its return value from the function call, if possible
|
|
318
|
+
if isinstance(x, str):
|
|
319
|
+
x = x.strip()
|
|
320
|
+
# let's check, AND SEE if the RETURN VALUE is FALSY
|
|
321
|
+
# if it is, head over to the except block, and return y
|
|
322
|
+
# otherwise, return x, as-is
|
|
323
|
+
if not x:
|
|
324
|
+
raise ValueError()
|
|
325
|
+
return x
|
|
326
|
+
except:
|
|
327
|
+
# upon failure,
|
|
328
|
+
# try the fallback
|
|
329
|
+
if y is not None and callable(y):
|
|
330
|
+
y = y()
|
|
331
|
+
# if callable,
|
|
332
|
+
# replace y with its return value from the function call, if possible
|
|
333
|
+
return y
|
|
334
|
+
koshish_nakami = koshish_nakaami = try_else
|
|
335
|
+
def collective_range(*lists: list[list]) -> list[int]:
|
|
336
|
+
lists = list(lists)
|
|
337
|
+
# converting the tuples to actual lists
|
|
338
|
+
# as Python varargs (*args)
|
|
339
|
+
# return a tuple (immutable)
|
|
340
|
+
# not a list
|
|
341
|
+
if not lists:
|
|
342
|
+
return []
|
|
343
|
+
lists = [lst for lst in lists if lst is not None and isinstance(lst, list)]
|
|
344
|
+
# filter
|
|
345
|
+
for i, lst in enumerate(lists):
|
|
346
|
+
if not isinstance(lists[i], list):
|
|
347
|
+
continue
|
|
348
|
+
lists[i] = range(len(lists[i]))
|
|
349
|
+
return collective_iter(*lists)
|
|
350
|
+
# this is going to be an improved version, a replacement of (random.)randint
|
|
351
|
+
# to avoid stack overflow, and cyclic references,
|
|
352
|
+
# let's store the old_randint function
|
|
353
|
+
from random import randint as old_randint, uniform as old_randflt
|
|
354
|
+
def rand_int(x: int = 10, y: int|None = None) -> int:
|
|
355
|
+
"""
|
|
356
|
+
Ek random integer generate karta he range `x` (zaruri), aur `y` (kaabile ignore) ke darmyaan.
|
|
357
|
+
A replacement to random.randint
|
|
358
|
+
@param x min (switchable with @param:y)
|
|
359
|
+
:type <int>
|
|
360
|
+
@param y max (switchable with @param:x)
|
|
361
|
+
:type <int, optional>
|
|
362
|
+
@return a random int
|
|
363
|
+
:type <int>
|
|
364
|
+
"""
|
|
365
|
+
if isinstance(x, float) and isinstance(y, float): return rand_flt(x, y)
|
|
366
|
+
if isinstance(x, float):
|
|
367
|
+
x = int(x)
|
|
368
|
+
if not isinstance(x, int):
|
|
369
|
+
x = 0
|
|
370
|
+
if y is not None:
|
|
371
|
+
if isinstance(y, float):
|
|
372
|
+
y = int(y)
|
|
373
|
+
if not isinstance(y, int):
|
|
374
|
+
y = 10
|
|
375
|
+
if y is None:
|
|
376
|
+
x, y = 0, x
|
|
377
|
+
# with type checks out of the way
|
|
378
|
+
# there shouldn't be a problem
|
|
379
|
+
# if we do:
|
|
380
|
+
x = int(x)
|
|
381
|
+
y = int(y)
|
|
382
|
+
if x == y:
|
|
383
|
+
return x
|
|
384
|
+
if y < x:
|
|
385
|
+
x, y = y, x
|
|
386
|
+
# let's make the make the function exclusive (of y itself)
|
|
387
|
+
result: int = 0
|
|
388
|
+
if y > x:
|
|
389
|
+
result = old_randint(x, y - 1)
|
|
390
|
+
else:
|
|
391
|
+
result = old_randint(y, x - 1)
|
|
392
|
+
return result
|
|
393
|
+
randint = koiint = koi_int = koinum = koi_num = koi_darmyan = randbetween = rand_between = randbw = rand_bw = randbelow = rand_below = rand_int
|
|
394
|
+
def rand_flt(x: float = 0, y: float|None = None, precision: int|None = None) -> float:
|
|
395
|
+
"""
|
|
396
|
+
A replacement to random.uniform
|
|
397
|
+
@param x min (or max if y is None)
|
|
398
|
+
:type <float>
|
|
399
|
+
@param y max (switchable with @param:x)
|
|
400
|
+
:type <float, optional>
|
|
401
|
+
@return a random int
|
|
402
|
+
:type <float>
|
|
403
|
+
"""
|
|
404
|
+
if not isinstance(x, (int, float)):
|
|
405
|
+
x = 0
|
|
406
|
+
if y is not None and not isinstance(y, (int, float)):
|
|
407
|
+
y = 1
|
|
408
|
+
x = float(x)
|
|
409
|
+
if y is not None:
|
|
410
|
+
y = float(y)
|
|
411
|
+
if not x and y is None:
|
|
412
|
+
x, y = 0, 1
|
|
413
|
+
if y is None:
|
|
414
|
+
x, y = 0.0, x
|
|
415
|
+
if x == y:
|
|
416
|
+
return x
|
|
417
|
+
if y < x:
|
|
418
|
+
x, y = y, x
|
|
419
|
+
# let's make the make the function exclusive (of y itself)
|
|
420
|
+
if y > 0:
|
|
421
|
+
y -= .1
|
|
422
|
+
else:
|
|
423
|
+
y += .1
|
|
424
|
+
if not precision or not isinstance(precision, int) or precision <= 0:
|
|
425
|
+
precision = 1
|
|
426
|
+
return round(old_randflt(x, y), precision)
|
|
427
|
+
randfloat = rand_float = randflt = koi_flt = koiflt = rand_flt
|
|
428
|
+
def choose(iterable: Iterable, n: int|None= None, koi: int|None=None) -> Any|list[Any]:
|
|
429
|
+
if koi is not None and isinstance(koi, int) and not isinstance(n, int):
|
|
430
|
+
n = abs(koi)
|
|
431
|
+
if isinstance(iterable, int) and isinstance(n, Iterable):
|
|
432
|
+
# cross compatibility: if the arguments
|
|
433
|
+
# are in reverse order
|
|
434
|
+
# order them
|
|
435
|
+
n, iterable = iterable, n
|
|
436
|
+
if not isinstance(iterable, Iterable):
|
|
437
|
+
return []
|
|
438
|
+
iterable = list(iterable)
|
|
439
|
+
if not len(iterable):
|
|
440
|
+
return [] if n != 1 else None
|
|
441
|
+
if isinstance(n, int) and n < 0:
|
|
442
|
+
n = abs(n)
|
|
443
|
+
if not n or not isinstance(n, int):
|
|
444
|
+
n = 1
|
|
445
|
+
if n > len(iterable):
|
|
446
|
+
n = len(iterable)
|
|
447
|
+
items: list[Any] = []
|
|
448
|
+
for _ in range(n):
|
|
449
|
+
items.append(iterable[rand_int(len(iterable))])
|
|
450
|
+
if isinstance(iterable, str):
|
|
451
|
+
return "".join(items)
|
|
452
|
+
if n == 1:
|
|
453
|
+
return items[0]
|
|
454
|
+
return items
|
|
455
|
+
choice = choices = choose_from = random_from = rand_from = rand_item = rand_items = rand_choice = choose_any = chuno = chuno_koi = koi = choose
|
|
456
|
+
def rand_range(start: int = 9, stop: int|None = None) -> list[int]:
|
|
457
|
+
"""
|
|
458
|
+
Generate a list of random integers.
|
|
459
|
+
- If stop is provided, generate a list of length abs(stop) with elements between start and stop (exclusive of stop).
|
|
460
|
+
- If stop is not provided, generate a list of length start with elements between 0 and start (exclusive of start)
|
|
461
|
+
- If nothing is provided, generate a list of 10 elements between 0 and 9 (inclusive).
|
|
462
|
+
@param start: The start of the range (inclusive) or length of list if stop is None.
|
|
463
|
+
@param stop: The end of the range (exclusive).
|
|
464
|
+
@return: A list of random integers.
|
|
465
|
+
"""
|
|
466
|
+
if not isinstance(start, int):
|
|
467
|
+
start = 9
|
|
468
|
+
if stop is None:
|
|
469
|
+
if start == 0:
|
|
470
|
+
return []
|
|
471
|
+
length = abs(start)
|
|
472
|
+
return [rand_int(0, start+1 if start > 0 else start-1) for _ in range(length)]
|
|
473
|
+
else:
|
|
474
|
+
if not isinstance(stop, int):
|
|
475
|
+
stop = 9
|
|
476
|
+
if stop < start:
|
|
477
|
+
start, stop = stop, start
|
|
478
|
+
length = abs(stop)
|
|
479
|
+
if start == stop:
|
|
480
|
+
return [start] * length # or handle this case differently
|
|
481
|
+
return [rand_int(start, stop) for _ in range(length)]
|
|
482
|
+
randrange = rand_range
|
|
483
|
+
def rand_str(length: int = 16) -> str:
|
|
484
|
+
if not isinstance(length, int) or length < 8:
|
|
485
|
+
length = 8
|
|
486
|
+
if length > 64:
|
|
487
|
+
length = 64
|
|
488
|
+
chars: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=_"
|
|
489
|
+
return_value: str = ""
|
|
490
|
+
for i in range(length):
|
|
491
|
+
return_value += chars[randint(0, len(chars)-1)]
|
|
492
|
+
return return_value
|
|
493
|
+
randstr = rand_str
|
|
494
|
+
def rand_hex(length: int = 16) -> str:
|
|
495
|
+
if not isinstance(length, int) or length < 8:
|
|
496
|
+
length = 8
|
|
497
|
+
if length > 64:
|
|
498
|
+
length = 64
|
|
499
|
+
chars: str = "0123456789abcdef"
|
|
500
|
+
return_value: str = ""
|
|
501
|
+
while length := length - 1:
|
|
502
|
+
return_value += chars[randint(0, len(chars)-1)]
|
|
503
|
+
return return_value
|
|
504
|
+
randhex = rand_hex
|
|
505
|
+
def rand_uuid() -> str:
|
|
506
|
+
from uuid import uuid4
|
|
507
|
+
return str(uuid4())
|
|
508
|
+
randuuid = rand_uuid
|
|
509
|
+
haal = filhal = filhaal = bool
|
|
510
|
+
line_break = linebreak = LINE_BREAK = LINEBREAK = "\n"
|
|
511
|
+
tab = TAB = "\t"
|
|
512
|
+
one_dim = two_dim = three_dim = four_dim = five_dim = \
|
|
513
|
+
six_dim = seven_dim = eight_dim = nine_dim = ten_dim = list
|
|
514
|
+
# recognizes all, just set it to `list`
|
|
515
|
+
# besides, the whole point of this
|
|
516
|
+
# is to achieve readability;
|
|
517
|
+
# will fail with `list|tuple|set`,
|
|
518
|
+
# and trust me, it has been tried
|
|
519
|
+
# to allow readable list-in-list, tuple-in-tuple types like the following:
|
|
520
|
+
# list[two_dim], list[three_dim], tuple[two_dim], tuple[three_dim]
|
|
521
|
+
# test:
|
|
522
|
+
# x: list[two_dim[int]] = [[1, 3, 5], [2, 4, 6]]
|
|
523
|
+
# print(x)
|
|
524
|
+
def intersection_of(x: list|dict, y: list|dict) -> list|dict:
|
|
525
|
+
if isinstance(x, tuple):
|
|
526
|
+
x = list(x)
|
|
527
|
+
if isinstance(y, tuple):
|
|
528
|
+
y = list(y)
|
|
529
|
+
if not isinstance(x, (list, dict)) and not isinstance(y, (list, dict)):
|
|
530
|
+
return []
|
|
531
|
+
if all(isinstance(each, list) for each in [x, y]):
|
|
532
|
+
return_val: list[Any] = list(set(x).intersection(y))
|
|
533
|
+
return_val.sort()
|
|
534
|
+
# list.sort returns None
|
|
535
|
+
return return_val
|
|
536
|
+
if all(isinstance(each, dict) for each in [x, y]):
|
|
537
|
+
return dict(x.items() & y.items())
|
|
538
|
+
return []
|
|
539
|
+
intersection = intersection_of
|
|
540
|
+
def if_main(main: Callable[[], None]) -> Callable[[], None]:
|
|
541
|
+
if callable(main) and main.__module__ == "__main__":
|
|
542
|
+
main()
|
|
543
|
+
return main
|
|
544
|
+
_entry = __entry = __entry__ = ifmain = if_main
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
class Date:
|
|
548
|
+
SEP: str = ", "
|
|
549
|
+
TIME_SEP: str = ":"
|
|
550
|
+
def __init__(self, date_string: Many[str, int, float, datetime.datetime, None] = None) -> None:
|
|
551
|
+
self.date_object: datetime.datetime
|
|
552
|
+
if isinstance(date_string, datetime.datetime):
|
|
553
|
+
self.date_object = date_string
|
|
554
|
+
if isinstance(date_string, (int, float)):
|
|
555
|
+
try:
|
|
556
|
+
self.date_object = datetime.datetime.fromtimestamp(date_string)
|
|
557
|
+
return
|
|
558
|
+
except (OverflowError, OSError, ValueError):
|
|
559
|
+
self.date_object = datetime.datetime.now()
|
|
560
|
+
return
|
|
561
|
+
if not isinstance(date_string, str):
|
|
562
|
+
self.date_object = datetime.datetime.now()
|
|
563
|
+
return
|
|
564
|
+
try:
|
|
565
|
+
date_string = re.sub(r"(?<=\d)\.(?=\d)", ":", date_string)
|
|
566
|
+
# replace is defined further below in the file
|
|
567
|
+
# better use original re.sub for safety
|
|
568
|
+
self.date_object = parse_date(date_string)
|
|
569
|
+
except ParserError:
|
|
570
|
+
print("Not a valid date string. Defaulting to today.")
|
|
571
|
+
self.date_object = datetime.datetime.now()
|
|
572
|
+
def __repr__(self, *args, **kwargs) -> str:
|
|
573
|
+
return self.format(*args, **kwargs)
|
|
574
|
+
__str__ = __repr__
|
|
575
|
+
# getters
|
|
576
|
+
def to_datetime(self) -> None:
|
|
577
|
+
return self.date_object
|
|
578
|
+
get_object = to_datetime
|
|
579
|
+
def format(self, short: bool = False, s: bool = False, short_year: bool = False, sep: str = SEP, time_sep: str = TIME_SEP) -> str:
|
|
580
|
+
if not isinstance(sep, str):
|
|
581
|
+
sep = self.SEP
|
|
582
|
+
if not isinstance(time_sep, str):
|
|
583
|
+
time_sep = self.TIME_SEP
|
|
584
|
+
date: datetime.datetime = self.date_object
|
|
585
|
+
format_for_short_dates: str = f"%I{time_sep}%M %p{sep}%a{sep}%b %d{sep}%{'Y' if not short_year else 'y'}"
|
|
586
|
+
format_for_longer_dates: str = f"%I{time_sep}%M{'' if not s else time_sep + '%S'} %p{sep}%A{sep}%B %d{sep}%{'Y' if not short_year else 'y'}"
|
|
587
|
+
formatted_date: str = ""
|
|
588
|
+
if short:
|
|
589
|
+
formatted_date = date.strftime(format_for_short_dates)
|
|
590
|
+
else:
|
|
591
|
+
formatted_date = date.strftime(format_for_longer_dates)
|
|
592
|
+
return formatted_date.lstrip("0").replace(" 0", " ")
|
|
593
|
+
get = get_long = long_get = get_full = full_get = read = full_read = read_full = long_read = read_long = read_long = long_read = f = _f = f_ = fmt = _str = str_ = _format = format_ = to_str = to_string = full = long = detailed = extended = full_form = long_form = detailed_form = extended_form = format
|
|
594
|
+
short = short_form = get_short = read_short = short_read = get_short = short_get = f_short = _f_short = f_short_ = fmt_short = _str_short = str_short = _format_short = format_short_ = partialmethod(format, short=True)
|
|
595
|
+
super_short = short_super = partialmethod(format, short=True, short_year=True)
|
|
596
|
+
super_super_short = short_super_super = super_duper_short = short_super_duper = lambda self: self.date_object.strftime("%I:%M %p, %a, %b %d, %y").lstrip("0")
|
|
597
|
+
short_almost_unreadable = almost_unreadable = inhuman_short = short_inhuman = inhumanly_short = short_inhumanly = insanely_short = short_insane = short_insanely = almost_unreadable_short = short_computerized = computerized_short = short_robotic = robotic_short = crazy_short = lambda self: self.date_object.strftime("%D")
|
|
598
|
+
def day(self, short: bool = False, short_year: bool = False, sep: str = SEP) -> str:
|
|
599
|
+
if isinstance(short, int)\
|
|
600
|
+
and not isinstance(short, bool)\
|
|
601
|
+
and short not in (True, False):
|
|
602
|
+
# if it's a true int, not a bool disguised as such
|
|
603
|
+
day: int = short
|
|
604
|
+
return self.set_day(day)
|
|
605
|
+
if not isinstance(sep, str):
|
|
606
|
+
sep = self.SEP
|
|
607
|
+
_today: str = self.format(
|
|
608
|
+
short=short,
|
|
609
|
+
short_year=short_year,
|
|
610
|
+
sep=sep
|
|
611
|
+
).split(sep, 1)[1]
|
|
612
|
+
return _today
|
|
613
|
+
date = d = long_timeless = timeless_long = long_wo_time = long_without_time = long_no_time = day
|
|
614
|
+
date_short = short_date = day_short = short_day = short_without_time = short_wo_time = timeless_short = short_timeless = short_no_time = partialmethod(day, short=True)
|
|
615
|
+
date_super_short = super_short_date = day_super_short = super_short_day = super_short_without_time = super_short_wo_time = timeless_super_short = super_short_timeless = super_short_no_time = partialmethod(day, short=True, short_year=True)
|
|
616
|
+
def day_only(self, short: bool = False) -> str:
|
|
617
|
+
name_of_day: str = self.day(short=short).split(",")[0].strip()
|
|
618
|
+
return name_of_day
|
|
619
|
+
day_name = day_of_week = dow = day_only
|
|
620
|
+
def day_number(self, short: bool = False) -> str:
|
|
621
|
+
day_number: str = self.day().split(",")[1].strip().split(" ")[1]
|
|
622
|
+
return int(day_number)
|
|
623
|
+
d_nr = day_nr = day_num = day_of_month = dom = day_number
|
|
624
|
+
def is_weekend(self) -> bool:
|
|
625
|
+
return self.day_only() in ("Saturday", "Sunday")
|
|
626
|
+
he_weekend = is_weekend
|
|
627
|
+
def is_weekday(self) -> bool:
|
|
628
|
+
return not self.is_weekend()
|
|
629
|
+
he_weekday = is_weekday
|
|
630
|
+
def month_only(self, short: bool = False) -> str:
|
|
631
|
+
if isinstance(short, int)\
|
|
632
|
+
and not isinstance(short, bool)\
|
|
633
|
+
and short not in (True, False):
|
|
634
|
+
# if it's a true int, not a bool disguised as such
|
|
635
|
+
month: int = short
|
|
636
|
+
return self.set_month(month)
|
|
637
|
+
name_of_month: str = self.day(
|
|
638
|
+
short=short
|
|
639
|
+
).split(", ")[1].split(" ")[0].strip()
|
|
640
|
+
return name_of_month
|
|
641
|
+
month_name = month = mn = month_only
|
|
642
|
+
def year_only(self, short: bool = False) -> str | int:
|
|
643
|
+
if isinstance(short, int)\
|
|
644
|
+
and not isinstance(short, bool)\
|
|
645
|
+
and short not in (True, False):
|
|
646
|
+
# if it's a true int, not a bool disguised as such
|
|
647
|
+
year: int = short
|
|
648
|
+
return self.set_year(year)
|
|
649
|
+
year_string: str = self.day()\
|
|
650
|
+
.split(", ")[-1].strip()
|
|
651
|
+
if short:
|
|
652
|
+
year_string = year_string[-2:]
|
|
653
|
+
# if short,
|
|
654
|
+
# return early
|
|
655
|
+
# so '2002' (str)
|
|
656
|
+
# now shortened into
|
|
657
|
+
# '02' doesn't end up
|
|
658
|
+
# 2 (now int)
|
|
659
|
+
return year_string
|
|
660
|
+
year: int = int(year_string)
|
|
661
|
+
return year
|
|
662
|
+
yr = year = year_only
|
|
663
|
+
def time(self, s: bool = False, time_sep: str = TIME_SEP) -> str:
|
|
664
|
+
if not isinstance(time_sep, str):
|
|
665
|
+
time_sep = self.TIME_SEP
|
|
666
|
+
return self.format(s=s, sep=self.SEP, time_sep=time_sep).split(self.SEP, 1)[0]
|
|
667
|
+
def time_and_day(self, s: bool = False, time_sep: str = TIME_SEP) -> str:
|
|
668
|
+
if not isinstance(time_sep, str):
|
|
669
|
+
time_sep = self.TIME_SEP
|
|
670
|
+
return self.format(s=s, sep=self.SEP, time_sep=time_sep).rsplit(self.SEP, 2)[0]
|
|
671
|
+
@classmethod
|
|
672
|
+
def now(cls) -> str:
|
|
673
|
+
return str(cls())
|
|
674
|
+
@classmethod
|
|
675
|
+
def time_now(cls, s: bool = False, time_sep: str = TIME_SEP) -> str:
|
|
676
|
+
return cls().time(s=s, time_sep=time_sep)
|
|
677
|
+
@classmethod
|
|
678
|
+
def today(cls, short: bool = False, sep: str = SEP) -> str:
|
|
679
|
+
return cls().day(short=short, sep=sep)
|
|
680
|
+
@classmethod
|
|
681
|
+
def day_today(cls, short: bool = False) -> str:
|
|
682
|
+
return cls().day_only(short=short)
|
|
683
|
+
# setters
|
|
684
|
+
def update(self, *args, **kwargs) -> Self:
|
|
685
|
+
self.date_object = self.date_object.replace(*args, **kwargs)
|
|
686
|
+
return self
|
|
687
|
+
replace = change = update
|
|
688
|
+
def set_year(self, year: int) -> Self:
|
|
689
|
+
if not isinstance(year, int) or year <= 0 or year > int(9.9e3):
|
|
690
|
+
raise TypeError("A year is supposed to be an int between 1 and 9999 (both inclusive)")
|
|
691
|
+
self.update(year=year)
|
|
692
|
+
return self
|
|
693
|
+
set_yr = set_year
|
|
694
|
+
def set_month(self, month: int) -> Self:
|
|
695
|
+
if not isinstance(month, int) or month <= 0 or month > 12:
|
|
696
|
+
raise TypeError("A month is supposed to be an int between 1 and 12 (both inclusive)")
|
|
697
|
+
self.update(month=month)
|
|
698
|
+
return self
|
|
699
|
+
set_mn = set_month
|
|
700
|
+
def set_day(self, day: int) -> Self:
|
|
701
|
+
if not isinstance(day, int) or day <= 0 or day > 31:
|
|
702
|
+
raise TypeError("A day is supposed to be an int between 1 and 31 (both inclusive)")
|
|
703
|
+
self.update(day=day)
|
|
704
|
+
return self
|
|
705
|
+
set_d = set_day
|
|
706
|
+
|
|
707
|
+
class Char(str):
|
|
708
|
+
def __new__(cls, value: Any):
|
|
709
|
+
if value is None:
|
|
710
|
+
return ""
|
|
711
|
+
character: str = ""
|
|
712
|
+
if isinstance(value, int|float):
|
|
713
|
+
character = chr(int(value))
|
|
714
|
+
else:
|
|
715
|
+
value = str(value).strip()
|
|
716
|
+
if not len(value):
|
|
717
|
+
return ""
|
|
718
|
+
character = value[0]
|
|
719
|
+
return super().__new__(cls, character)
|
|
720
|
+
char = Char
|
|
721
|
+
Str = lafz = jumla = lambda x: str(x).strip() # trim the string after parsing
|
|
722
|
+
# no one needs additional whitespace
|
|
723
|
+
nr = num = Num = Nr = Number
|
|
724
|
+
INFINITY = Infinity = infinity = Inf = inf
|
|
725
|
+
INT_INFINITY = INTEGER_INFINITY = INTINFINITY = INTEGERINFINITY = IntInfinity = Int_Infinity = int_infinity = intinfinity = int_inf = IntInf = intinf = sys.maxsize
|
|
726
|
+
goto = open_link = link_kholo = kholo_link = webbrowser.open
|
|
727
|
+
link = webbrowser
|
|
728
|
+
_dir = os.getcwd()
|
|
729
|
+
# crucial \/
|
|
730
|
+
class AbstractMethodsRehteHeError(TypeError):
|
|
731
|
+
def __init__(self, name: str):
|
|
732
|
+
self.name = str(name)
|
|
733
|
+
super().__init__(self.name)
|
|
734
|
+
class AbstractBaseClassMeta(ABCMeta):
|
|
735
|
+
def __new__(mcs, name, bases, namespace, **kwargs):
|
|
736
|
+
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
|
|
737
|
+
if ABCMeta in cls.__mro__ and cls.__abstractmethods__:
|
|
738
|
+
return cls
|
|
739
|
+
abstract_methods: set = set()
|
|
740
|
+
for base in bases:
|
|
741
|
+
if isinstance(base, ABCMeta):
|
|
742
|
+
abstract_methods.update(base.__abstractmethods__)
|
|
743
|
+
missing_methods = abstract_methods - set(cls.__dict__)
|
|
744
|
+
for method_name in abstract_methods:
|
|
745
|
+
if not any(method_name in base.__dict__ for base in inspect.getmro(cls)[1:]):
|
|
746
|
+
missing_methods.add(method_name)
|
|
747
|
+
if missing_methods:
|
|
748
|
+
raise AbstractMethodsRehteHeError(
|
|
749
|
+
f"Base class '{name}' ke methods {missing_methods} ko implement karna laazmi he"
|
|
750
|
+
)
|
|
751
|
+
for method_name in abstract_methods:
|
|
752
|
+
if method_name not in cls.__dict__ :
|
|
753
|
+
continue
|
|
754
|
+
subclass_method = cls.__dict__[method_name]
|
|
755
|
+
for base in inspect.getmro(cls)[1:]:
|
|
756
|
+
if method_name not in base.__dict__:
|
|
757
|
+
continue
|
|
758
|
+
base_method = base.__dict__[method_name]
|
|
759
|
+
base_method_type = inspect.signature(base_method)
|
|
760
|
+
subclass_method_type = inspect.signature(subclass_method)
|
|
761
|
+
if base_method_type == subclass_method_type:
|
|
762
|
+
continue
|
|
763
|
+
raise TypeError(
|
|
764
|
+
f"Concrete class '{name}' ke method '{method_name}' ka kism BASE CLASS '{base.__name__}' ke sath match nahi karta"
|
|
765
|
+
)
|
|
766
|
+
return cls
|
|
767
|
+
# preserve the sequence
|
|
768
|
+
# it MATTERS
|
|
769
|
+
def extends_from(_object: Any, target: Any) -> bool:
|
|
770
|
+
"""
|
|
771
|
+
checks if @_object extends from (or isinstance of) @super_class
|
|
772
|
+
DIFFERENT FROM regular `__builtins__.isinstance`
|
|
773
|
+
in the sense that `__builtins__.isinstance` only tells you if an object x
|
|
774
|
+
is strictly of type --- or an "instance" initiated directly from class --- y
|
|
775
|
+
@param _object
|
|
776
|
+
::type Any/type type (class)
|
|
777
|
+
::desc an object or a class to test if it extends from (or at least belongs to) class @target
|
|
778
|
+
@param target
|
|
779
|
+
::type Any/type type (class)
|
|
780
|
+
::desc the target class
|
|
781
|
+
@return
|
|
782
|
+
::type bool
|
|
783
|
+
::desc returns True if @_object extends from @target
|
|
784
|
+
|
|
785
|
+
Reads like: 'If X extends_from Y', or 'If X belongs_to Y'
|
|
786
|
+
Handles both instances (isinstance), and classes (issubclass).
|
|
787
|
+
"""
|
|
788
|
+
if isinstance(target, (list, tuple, UnionType)):
|
|
789
|
+
sub_targets: list[Any] = target.__args__ if isinstance(target, UnionType) else target
|
|
790
|
+
return any(extends_from(_object, sub_target) for sub_target in sub_targets)
|
|
791
|
+
if isinstance(_object, (list, tuple, set)) and not isinstance(_object, (str, bytes)):
|
|
792
|
+
if len(_object) == 0:
|
|
793
|
+
return False
|
|
794
|
+
return all(extends_from(item, target) for item in _object)
|
|
795
|
+
# kill int-on-bool, bool-on-int false-positive checks
|
|
796
|
+
if target is int and isinstance(_object, bool):
|
|
797
|
+
return False
|
|
798
|
+
if target is int and _object is bool:
|
|
799
|
+
return False
|
|
800
|
+
if isinstance(_object, type) or hasattr(_object, "__origin__"):
|
|
801
|
+
try:
|
|
802
|
+
# Handle Generic Aliases like list[int] which issubclass() can reject
|
|
803
|
+
_object = get_origin(_object) or _object
|
|
804
|
+
target = get_origin(target) or target
|
|
805
|
+
return issubclass(_object, target)
|
|
806
|
+
except TypeError:
|
|
807
|
+
return False
|
|
808
|
+
# if _object is an object, check if it's an instance of target
|
|
809
|
+
try:
|
|
810
|
+
return isinstance(_object, target)
|
|
811
|
+
except TypeError:
|
|
812
|
+
return False
|
|
813
|
+
belongs_to = he_sub_class = sub_class_he = he_kism = extends_from
|
|
814
|
+
# ^^much needed
|
|
815
|
+
def kism(x: Any) -> type:
|
|
816
|
+
return get_origin(x) or type(x)
|
|
817
|
+
he_kism = hekism = is_type = istype = lambda y, x: kism(x) == y
|
|
818
|
+
# keep the order
|
|
819
|
+
def __ltype_helper_fn__(o: object) -> str:
|
|
820
|
+
try:
|
|
821
|
+
cls = o if isinstance(o, type) else type(o)
|
|
822
|
+
name = getattr(cls, "__name__", "unknown")
|
|
823
|
+
name = re.sub(r"^(?:KL(?:_Py)?[\._]|datetime\.|__main\.)", "", name)
|
|
824
|
+
type_normalization = {
|
|
825
|
+
"str_": "str",
|
|
826
|
+
"float64": "float", "float32": "float", "float16": "float",
|
|
827
|
+
"int64": "int", "int32": "int", "int16": "int", "int8": "int",
|
|
828
|
+
"bool_": "bool"
|
|
829
|
+
}
|
|
830
|
+
return type_normalization.get(name, name)
|
|
831
|
+
except Exception:
|
|
832
|
+
return "unknown"
|
|
833
|
+
def ltype(o: object, max_depth: int = 6, _current_depth: int = 0) -> str:
|
|
834
|
+
if _current_depth > max_depth:
|
|
835
|
+
return "..."
|
|
836
|
+
parsed_type = __ltype_helper_fn__(o)
|
|
837
|
+
if (not isinstance(o, Iterable) or
|
|
838
|
+
isinstance(o, (str, bytes, bytearray, memoryview, Generator, Iterator, zip, map, builtins.filter, enumerate))):
|
|
839
|
+
return parsed_type
|
|
840
|
+
try:
|
|
841
|
+
if callable(getattr(o, "__len__", None)) and not len(o):
|
|
842
|
+
return parsed_type
|
|
843
|
+
except Exception:
|
|
844
|
+
pass
|
|
845
|
+
if isinstance(o, Mapping):
|
|
846
|
+
try:
|
|
847
|
+
items_snapshot = list(o.items())
|
|
848
|
+
except (KeyboardInterrupt, SystemExit):
|
|
849
|
+
raise
|
|
850
|
+
except Exception:
|
|
851
|
+
return parsed_type
|
|
852
|
+
filtered_items = [
|
|
853
|
+
(k, v) for k, v in items_snapshot
|
|
854
|
+
if not (isinstance(k, str) and re.search(r"^\b(?:k[aeio]|mese)\b$", k))
|
|
855
|
+
]
|
|
856
|
+
if not filtered_items:
|
|
857
|
+
return parsed_type
|
|
858
|
+
first_k, first_v = filtered_items[0]
|
|
859
|
+
if id(o) == id(first_v):
|
|
860
|
+
return f"{parsed_type}[{__ltype_helper_fn__(first_k)}, ...]"
|
|
861
|
+
first_k_type, first_v_type = type(first_k), type(first_v)
|
|
862
|
+
supported_key_types = (str, int, float, bool)
|
|
863
|
+
if first_k_type in supported_key_types:
|
|
864
|
+
try:
|
|
865
|
+
if all(type(k) is first_k_type for k, _ in filtered_items):
|
|
866
|
+
if all(type(v) is first_v_type for _, v in filtered_items):
|
|
867
|
+
return f"{parsed_type}[{__ltype_helper_fn__(first_k)}, {ltype(first_v, max_depth, _current_depth + 1)}]"
|
|
868
|
+
except (KeyboardInterrupt, SystemExit):
|
|
869
|
+
raise
|
|
870
|
+
except Exception:
|
|
871
|
+
pass
|
|
872
|
+
return parsed_type
|
|
873
|
+
try:
|
|
874
|
+
iterator = iter(o)
|
|
875
|
+
first_item = next(iterator)
|
|
876
|
+
except (StopIteration, KeyboardInterrupt, SystemExit):
|
|
877
|
+
if isinstance(sys.exc_info()[0], (KeyboardInterrupt, SystemExit)):
|
|
878
|
+
raise
|
|
879
|
+
return parsed_type
|
|
880
|
+
except Exception:
|
|
881
|
+
return parsed_type
|
|
882
|
+
if id(o) == id(first_item):
|
|
883
|
+
return f"{parsed_type}[...]"
|
|
884
|
+
first_type = type(first_item)
|
|
885
|
+
try:
|
|
886
|
+
for item in iterator:
|
|
887
|
+
if type(item) is not first_type:
|
|
888
|
+
return parsed_type
|
|
889
|
+
except (KeyboardInterrupt, SystemExit):
|
|
890
|
+
raise
|
|
891
|
+
except Exception:
|
|
892
|
+
return parsed_type
|
|
893
|
+
return f"{parsed_type}[{ltype(first_item, max_depth, _current_depth + 1)}]"
|
|
894
|
+
pakki_kism = pkism = literal_kism = lkism = literal_type = ltype
|
|
895
|
+
def ltype_old(o: object) -> str:
|
|
896
|
+
try:
|
|
897
|
+
parsed_type: str = re.split(r"[\"\']", str(type(o)))[1]
|
|
898
|
+
except IndexError:
|
|
899
|
+
return "unknown"
|
|
900
|
+
if re.search(r"^(?:KL(?:_Py)?|datetime|__main__)\.(?=[A-Za-z_])", parsed_type):
|
|
901
|
+
parsed_type = parsed_type.split(".", maxsplit=1)[1]
|
|
902
|
+
if not isinstance(o, Iterable) or isinstance(o, (Generator, Iterator, zip, map, builtins.filter, enumerate)) or (callable(getattr(o, "__len__", None)) and not len(o)):
|
|
903
|
+
return parsed_type
|
|
904
|
+
if re.search(r"\b(?:list|tuple|(?:frozen)?set|(?:p(?:an)?d(?:as)?\.)?(?:Custom)?Series|(?:n(?:um)?py?\.)?ndarray|dict_(?:keys|values))\b", parsed_type):
|
|
905
|
+
if all(isinstance(item, list) for item in o):
|
|
906
|
+
parsed_type += "[list]"
|
|
907
|
+
elif all(isinstance(item, tuple) for item in o):
|
|
908
|
+
parsed_type += "[tuple]"
|
|
909
|
+
elif all(isinstance(item, set) for item in o):
|
|
910
|
+
parsed_type += "[set]"
|
|
911
|
+
elif all(isinstance(item, frozenset) for item in o):
|
|
912
|
+
parsed_type += "[frozenset]"
|
|
913
|
+
elif all(isinstance(item, dict) for item in o):
|
|
914
|
+
parsed_type += "[dict]"
|
|
915
|
+
elif all(isinstance(item, str) for item in o):
|
|
916
|
+
parsed_type += "[str]"
|
|
917
|
+
elif all(isinstance(item, int) or re.search(r"(?:n(?:um)?py?)?\.int\d*", str(type(item))) for item in o):
|
|
918
|
+
parsed_type += "[int]"
|
|
919
|
+
elif all(isinstance(item, float) or re.search(r"(?:n(?:um)?py?)?\.float\d*", str(type(item))) for item in o):
|
|
920
|
+
parsed_type += "[float]"
|
|
921
|
+
elif all(isinstance(item, bool) for item in o):
|
|
922
|
+
parsed_type += "[bool]"
|
|
923
|
+
elif all(isinstance(item, datetime.datetime) for item in o):
|
|
924
|
+
parsed_type += "[datetime]"
|
|
925
|
+
elif all(re.search(r"\b(?:KL(?:_Py)?\.)?Date\b", str(type(item))) for item in o):
|
|
926
|
+
parsed_type += "[Date]"
|
|
927
|
+
elif all(isinstance(item, type(None)) for item in o):
|
|
928
|
+
parsed_type += "[None]"
|
|
929
|
+
elif re.search(r"\b(?:dict|(?:KL(?:_Py)?\.)?obj)\b", parsed_type):
|
|
930
|
+
keys = [k for k, v in o.items() if not re.search(r"^\bk[aeio]\b$", str(k))]
|
|
931
|
+
if not len(keys):
|
|
932
|
+
return parsed_type
|
|
933
|
+
if all(isinstance(item, str) for item in keys):
|
|
934
|
+
parsed_type += "[str"
|
|
935
|
+
elif all(isinstance(item, int) for item in keys):
|
|
936
|
+
parsed_type += "[int"
|
|
937
|
+
elif all(isinstance(item, float) for item in keys):
|
|
938
|
+
parsed_type += "[float"
|
|
939
|
+
elif all(isinstance(item, bool) for item in keys):
|
|
940
|
+
parsed_type += "[bool"
|
|
941
|
+
parsed_type += ", "
|
|
942
|
+
values = [v for k, v in o.items() if not re.search(r"^\bk[aeio]\b$", str(k))]
|
|
943
|
+
if all(isinstance(item, list) for item in values):
|
|
944
|
+
parsed_type += "list"
|
|
945
|
+
elif all(isinstance(item, tuple) for item in values):
|
|
946
|
+
parsed_type += "tuple"
|
|
947
|
+
elif all(isinstance(item, set) for item in values):
|
|
948
|
+
parsed_type += "set"
|
|
949
|
+
elif all(isinstance(item, frozenset) for item in values):
|
|
950
|
+
parsed_type += "frozenset"
|
|
951
|
+
elif all(isinstance(item, dict) for item in values):
|
|
952
|
+
parsed_type += "dict"
|
|
953
|
+
elif all(isinstance(item, str) for item in values):
|
|
954
|
+
parsed_type += "str"
|
|
955
|
+
elif all(isinstance(item, int) for item in values):
|
|
956
|
+
parsed_type += "int"
|
|
957
|
+
elif all(isinstance(item, float) for item in values):
|
|
958
|
+
parsed_type += "float"
|
|
959
|
+
elif all(isinstance(item, bool) for item in values):
|
|
960
|
+
parsed_type += "bool"
|
|
961
|
+
elif all(isinstance(item, datetime.datetime) for item in values):
|
|
962
|
+
parsed_type += "datetime"
|
|
963
|
+
elif all(re.search(r"\b(?:KL(?:_Py)?\.)?Date\b", str(type(item))) for item in values):
|
|
964
|
+
parsed_type += "Date"
|
|
965
|
+
elif all(isinstance(item, type(None)) for item in values):
|
|
966
|
+
parsed_type += "None"
|
|
967
|
+
if re.search(r"\[\w+, *$", parsed_type.strip()):
|
|
968
|
+
parsed_type = parsed_type.split("[")[0]
|
|
969
|
+
else:
|
|
970
|
+
parsed_type += "]"
|
|
971
|
+
if re.search(r", *]$", parsed_type.strip()):
|
|
972
|
+
parsed_type = re.sub(r", *]$", "", parsed_type)
|
|
973
|
+
return parsed_type
|
|
974
|
+
# preserve the sequence
|
|
975
|
+
# it MATTERS
|
|
976
|
+
def hissa(item: Any|type, container: Any|type|Iterable, _seen: Optional[set[int]] = None) -> bool:
|
|
977
|
+
try:
|
|
978
|
+
if _seen is None:
|
|
979
|
+
_seen = set()
|
|
980
|
+
container_id = id(container)
|
|
981
|
+
if container_id in _seen:
|
|
982
|
+
return False # Already checked this exact container
|
|
983
|
+
_seen.add(container_id)
|
|
984
|
+
if isinstance(item, str) and isinstance(container, str):
|
|
985
|
+
return match_i(container, item)
|
|
986
|
+
# NOTE: keep the order like this
|
|
987
|
+
# has to be called in reverse
|
|
988
|
+
# the parameters of this function are
|
|
989
|
+
# in reverse for readability
|
|
990
|
+
item_is_type_type: bool = isinstance(item, type) or hasattr(item, "__origin__")
|
|
991
|
+
container_is_type_type: bool = isinstance(container, type) or hasattr(container, "__origin__")
|
|
992
|
+
if item_is_type_type and container_is_type_type:
|
|
993
|
+
return extends_from(container, item)
|
|
994
|
+
if isinstance(container, (list, tuple, set, collections.abc.Iterable)):
|
|
995
|
+
if item_is_type_type:
|
|
996
|
+
return any(extends_from(parent, item) for parent in container if isinstance(parent, type) or hasattr(parent, "__origin__"))
|
|
997
|
+
try:
|
|
998
|
+
# direct membership check first (fast)
|
|
999
|
+
if item in container:
|
|
1000
|
+
return True
|
|
1001
|
+
except TypeError:
|
|
1002
|
+
pass
|
|
1003
|
+
for element in container:
|
|
1004
|
+
if isinstance(element, (list, tuple, set, dict)):
|
|
1005
|
+
if hissa(item, element, _seen=_seen):
|
|
1006
|
+
return True
|
|
1007
|
+
elif item == element:
|
|
1008
|
+
return True
|
|
1009
|
+
return item == container
|
|
1010
|
+
except (TypeError, ValueError, AttributeError):
|
|
1011
|
+
return False
|
|
1012
|
+
# preserve the sequence
|
|
1013
|
+
# it MATTERS
|
|
1014
|
+
def isinstance_each(collection: Any, target: Any) -> bool:
|
|
1015
|
+
"""
|
|
1016
|
+
WARNING:
|
|
1017
|
+
this is DIFFERENT from `__builtins__.isinstance`
|
|
1018
|
+
HERE'S HOW: it shortens multiple isinstance checks into one
|
|
1019
|
+
WHERE y is the type to compare each item in x with.
|
|
1020
|
+
So, unlike the original...
|
|
1021
|
+
this one won't return True for
|
|
1022
|
+
`isinstance([1, 2], list)`
|
|
1023
|
+
unlike the original!
|
|
1024
|
+
INSTEAD:
|
|
1025
|
+
this one checks if every item from the @collection on the left
|
|
1026
|
+
matches the type of the @target
|
|
1027
|
+
Here is what it WILL return True for:
|
|
1028
|
+
isinstance_each([1, 2], int) // output: True
|
|
1029
|
+
isinstance_each([1.2, 2.1], float) // output: True
|
|
1030
|
+
isinstance_each([1.2, 2], float) // output: False, since 2 is an int
|
|
1031
|
+
|
|
1032
|
+
:: Checks if every item in @collection belongs_to @target.
|
|
1033
|
+
:: Returns False if the collection is empty.
|
|
1034
|
+
:: Also works with classes: isinstance_each([ValueError, TypeError], Exception) returns True
|
|
1035
|
+
"""
|
|
1036
|
+
if not isinstance(collection, (list, tuple, set)):
|
|
1037
|
+
return False
|
|
1038
|
+
return extends_from(collection, target)
|
|
1039
|
+
each_isinstance = each_is_instance = is_instance_each = isinstance_each
|
|
1040
|
+
from bisect import bisect_left
|
|
1041
|
+
def near_get(
|
|
1042
|
+
d: dict,
|
|
1043
|
+
k: Union[str, int, float],
|
|
1044
|
+
default=None
|
|
1045
|
+
):
|
|
1046
|
+
if not isinstance(d, dict)\
|
|
1047
|
+
or not d\
|
|
1048
|
+
or type(k) not in (
|
|
1049
|
+
str,
|
|
1050
|
+
int,
|
|
1051
|
+
float
|
|
1052
|
+
):
|
|
1053
|
+
return default
|
|
1054
|
+
if k in d:
|
|
1055
|
+
return d[
|
|
1056
|
+
k
|
|
1057
|
+
]
|
|
1058
|
+
if isinstance(k, str):
|
|
1059
|
+
k_lower: str = k.lower()
|
|
1060
|
+
str_keys = [
|
|
1061
|
+
str(key)\
|
|
1062
|
+
for key in d\
|
|
1063
|
+
if isinstance(key, str)
|
|
1064
|
+
]
|
|
1065
|
+
if not str_keys:
|
|
1066
|
+
return default
|
|
1067
|
+
for key in str_keys:
|
|
1068
|
+
if key\
|
|
1069
|
+
.lower() == k_lower:
|
|
1070
|
+
return d[
|
|
1071
|
+
key
|
|
1072
|
+
]
|
|
1073
|
+
for key in sorted(
|
|
1074
|
+
str_keys
|
|
1075
|
+
):
|
|
1076
|
+
if key\
|
|
1077
|
+
.lower()\
|
|
1078
|
+
.startswith(
|
|
1079
|
+
k_lower
|
|
1080
|
+
):
|
|
1081
|
+
return d[
|
|
1082
|
+
key
|
|
1083
|
+
]
|
|
1084
|
+
for key in sorted(
|
|
1085
|
+
str_keys,
|
|
1086
|
+
key=len,
|
|
1087
|
+
reverse=True
|
|
1088
|
+
):
|
|
1089
|
+
if k_lower\
|
|
1090
|
+
.startswith(
|
|
1091
|
+
key\
|
|
1092
|
+
.lower()
|
|
1093
|
+
):
|
|
1094
|
+
return d[
|
|
1095
|
+
key
|
|
1096
|
+
]
|
|
1097
|
+
else:
|
|
1098
|
+
k_int: int = int(
|
|
1099
|
+
k
|
|
1100
|
+
)
|
|
1101
|
+
if k_int in d:
|
|
1102
|
+
return d[
|
|
1103
|
+
k_int
|
|
1104
|
+
]
|
|
1105
|
+
num_keys_map = {}
|
|
1106
|
+
for key in d:
|
|
1107
|
+
if isinstance(
|
|
1108
|
+
key,
|
|
1109
|
+
(
|
|
1110
|
+
int,
|
|
1111
|
+
float
|
|
1112
|
+
)
|
|
1113
|
+
):
|
|
1114
|
+
num_keys_map[
|
|
1115
|
+
int(key)
|
|
1116
|
+
] = key
|
|
1117
|
+
if not num_keys_map:
|
|
1118
|
+
return default
|
|
1119
|
+
sorted_ints = sorted(
|
|
1120
|
+
num_keys_map\
|
|
1121
|
+
.keys()
|
|
1122
|
+
)
|
|
1123
|
+
if k_int < sorted_ints[
|
|
1124
|
+
0
|
|
1125
|
+
]:
|
|
1126
|
+
return d[
|
|
1127
|
+
num_keys_map[
|
|
1128
|
+
sorted_ints[
|
|
1129
|
+
0
|
|
1130
|
+
]
|
|
1131
|
+
]
|
|
1132
|
+
]
|
|
1133
|
+
if k_int > sorted_ints[
|
|
1134
|
+
-1
|
|
1135
|
+
]:
|
|
1136
|
+
return d[
|
|
1137
|
+
num_keys_map[
|
|
1138
|
+
sorted_ints[
|
|
1139
|
+
-1
|
|
1140
|
+
]
|
|
1141
|
+
]
|
|
1142
|
+
]
|
|
1143
|
+
pos = bisect_left(
|
|
1144
|
+
sorted_ints,
|
|
1145
|
+
k_int
|
|
1146
|
+
)
|
|
1147
|
+
candidates = [
|
|
1148
|
+
sorted_ints[
|
|
1149
|
+
pos - 1
|
|
1150
|
+
],
|
|
1151
|
+
sorted_ints[
|
|
1152
|
+
pos
|
|
1153
|
+
]
|
|
1154
|
+
]\
|
|
1155
|
+
if pos < len(
|
|
1156
|
+
sorted_ints
|
|
1157
|
+
)\
|
|
1158
|
+
else [
|
|
1159
|
+
sorted_ints[
|
|
1160
|
+
pos - 1
|
|
1161
|
+
]
|
|
1162
|
+
]
|
|
1163
|
+
closest_int = min(
|
|
1164
|
+
candidates,
|
|
1165
|
+
key=lambda x:\
|
|
1166
|
+
abs(
|
|
1167
|
+
x - k_int
|
|
1168
|
+
)
|
|
1169
|
+
)
|
|
1170
|
+
if abs(
|
|
1171
|
+
closest_int - k_int
|
|
1172
|
+
) <= 3:
|
|
1173
|
+
return d[
|
|
1174
|
+
num_keys_map[
|
|
1175
|
+
closest_int
|
|
1176
|
+
]
|
|
1177
|
+
]
|
|
1178
|
+
return default
|
|
1179
|
+
def safe_get(
|
|
1180
|
+
data: Any,
|
|
1181
|
+
path: str | list | tuple,
|
|
1182
|
+
default: Any = None,
|
|
1183
|
+
target_type: Any = object,
|
|
1184
|
+
ignore_case: bool = True,
|
|
1185
|
+
use_regex: bool = False,
|
|
1186
|
+
auto_flatten: bool = False,
|
|
1187
|
+
on_match: Optional[Callable[[Any], Any]] = None,
|
|
1188
|
+
deep_search: bool = True,
|
|
1189
|
+
max_depth: int = 20,
|
|
1190
|
+
_seen: Optional[set[int]] = None
|
|
1191
|
+
) -> Any:
|
|
1192
|
+
if isinstance(data, dict):
|
|
1193
|
+
# add a fallback
|
|
1194
|
+
# if dictionary
|
|
1195
|
+
# get the closest key
|
|
1196
|
+
# if nothing works out
|
|
1197
|
+
default = close_get(d=data, k=path, default=default)
|
|
1198
|
+
if _seen is None:
|
|
1199
|
+
_seen = set()
|
|
1200
|
+
if max_depth < 0:
|
|
1201
|
+
return default
|
|
1202
|
+
if isinstance(path, str) and '.' in path:
|
|
1203
|
+
parts: list[str] = path.split('.')
|
|
1204
|
+
if deep_search:
|
|
1205
|
+
path = parts[-1]
|
|
1206
|
+
else:
|
|
1207
|
+
path = parts[0]
|
|
1208
|
+
if isinstance(path, (list, tuple)) and not deep_search:
|
|
1209
|
+
if len(path) > 0 and any(isinstance(p, (str, list, tuple)) for p in path):
|
|
1210
|
+
is_multi = any(
|
|
1211
|
+
'.' in p\
|
|
1212
|
+
if isinstance(p, str)\
|
|
1213
|
+
else True\
|
|
1214
|
+
for p in path
|
|
1215
|
+
)
|
|
1216
|
+
if is_multi:
|
|
1217
|
+
return [
|
|
1218
|
+
safe_get(
|
|
1219
|
+
data,
|
|
1220
|
+
p,
|
|
1221
|
+
default,
|
|
1222
|
+
target_type,
|
|
1223
|
+
ignore_case,
|
|
1224
|
+
use_regex,
|
|
1225
|
+
auto_flatten,
|
|
1226
|
+
on_match,
|
|
1227
|
+
deep_search,
|
|
1228
|
+
max_depth,
|
|
1229
|
+
_seen.copy()
|
|
1230
|
+
) for p in path
|
|
1231
|
+
]
|
|
1232
|
+
if isinstance(
|
|
1233
|
+
data,
|
|
1234
|
+
(
|
|
1235
|
+
list,
|
|
1236
|
+
tuple,
|
|
1237
|
+
dict,
|
|
1238
|
+
set
|
|
1239
|
+
)
|
|
1240
|
+
):
|
|
1241
|
+
if id(data) in _seen:
|
|
1242
|
+
return default
|
|
1243
|
+
_seen.add(
|
|
1244
|
+
id(data)
|
|
1245
|
+
)
|
|
1246
|
+
def _run_finalize(val):
|
|
1247
|
+
if auto_flatten:
|
|
1248
|
+
def _gen_flatten(items):
|
|
1249
|
+
if isinstance(
|
|
1250
|
+
items,
|
|
1251
|
+
(
|
|
1252
|
+
list,
|
|
1253
|
+
tuple,
|
|
1254
|
+
set
|
|
1255
|
+
)
|
|
1256
|
+
):
|
|
1257
|
+
for item in items:
|
|
1258
|
+
yield from _gen_flatten(
|
|
1259
|
+
item
|
|
1260
|
+
)
|
|
1261
|
+
else:
|
|
1262
|
+
yield items
|
|
1263
|
+
val = list(
|
|
1264
|
+
_gen_flatten(
|
|
1265
|
+
val
|
|
1266
|
+
)
|
|
1267
|
+
)
|
|
1268
|
+
if on_match\
|
|
1269
|
+
and val is not default:
|
|
1270
|
+
try:
|
|
1271
|
+
val = [
|
|
1272
|
+
on_match(i)\
|
|
1273
|
+
for i in val
|
|
1274
|
+
]\
|
|
1275
|
+
if auto_flatten\
|
|
1276
|
+
else on_match(val)
|
|
1277
|
+
except:
|
|
1278
|
+
return default
|
|
1279
|
+
if val is not None\
|
|
1280
|
+
and target_type is not object:
|
|
1281
|
+
if auto_flatten:
|
|
1282
|
+
if "isinstance_each" in globals()\
|
|
1283
|
+
and not isinstance_each(
|
|
1284
|
+
val,
|
|
1285
|
+
target_type
|
|
1286
|
+
):
|
|
1287
|
+
return default
|
|
1288
|
+
else:
|
|
1289
|
+
if "extends_from" in globals()\
|
|
1290
|
+
and not extends_from(
|
|
1291
|
+
val,
|
|
1292
|
+
target_type
|
|
1293
|
+
):
|
|
1294
|
+
return default
|
|
1295
|
+
return val
|
|
1296
|
+
def _find_key(d, k):
|
|
1297
|
+
if use_regex:
|
|
1298
|
+
try:
|
|
1299
|
+
p = re.compile(
|
|
1300
|
+
str(k),
|
|
1301
|
+
re.IGNORECASE\
|
|
1302
|
+
if ignore_case\
|
|
1303
|
+
else 0
|
|
1304
|
+
)
|
|
1305
|
+
for existing_key in d:
|
|
1306
|
+
if p.search(
|
|
1307
|
+
str(
|
|
1308
|
+
existing_key
|
|
1309
|
+
)
|
|
1310
|
+
):
|
|
1311
|
+
return d[
|
|
1312
|
+
existing_key
|
|
1313
|
+
]
|
|
1314
|
+
except re.error:
|
|
1315
|
+
pass
|
|
1316
|
+
elif ignore_case:
|
|
1317
|
+
k_map = {
|
|
1318
|
+
str(key).lower(): key\
|
|
1319
|
+
for key in d.keys()
|
|
1320
|
+
}
|
|
1321
|
+
look = k_map.get(
|
|
1322
|
+
str(k)\
|
|
1323
|
+
.lower()
|
|
1324
|
+
)
|
|
1325
|
+
if look is not None:
|
|
1326
|
+
return d[
|
|
1327
|
+
look
|
|
1328
|
+
]
|
|
1329
|
+
return d\
|
|
1330
|
+
.get(k)\
|
|
1331
|
+
if isinstance(d, dict)\
|
|
1332
|
+
else None
|
|
1333
|
+
if deep_search:
|
|
1334
|
+
target_key = path\
|
|
1335
|
+
if isinstance(path, (list, tuple))\
|
|
1336
|
+
else str(path)
|
|
1337
|
+
if isinstance(data, dict):
|
|
1338
|
+
found = _find_key(
|
|
1339
|
+
data,
|
|
1340
|
+
target_key
|
|
1341
|
+
)
|
|
1342
|
+
if found is not None:
|
|
1343
|
+
return _run_finalize(
|
|
1344
|
+
found
|
|
1345
|
+
)
|
|
1346
|
+
for v in data.values():
|
|
1347
|
+
res = safe_get(
|
|
1348
|
+
v,
|
|
1349
|
+
path,
|
|
1350
|
+
default,
|
|
1351
|
+
target_type,
|
|
1352
|
+
ignore_case,
|
|
1353
|
+
use_regex,
|
|
1354
|
+
auto_flatten,
|
|
1355
|
+
on_match,
|
|
1356
|
+
True,
|
|
1357
|
+
max_depth - 1,
|
|
1358
|
+
_seen
|
|
1359
|
+
)
|
|
1360
|
+
if res is not default:
|
|
1361
|
+
return res
|
|
1362
|
+
elif isinstance(data, (list, tuple)):
|
|
1363
|
+
for item in data:
|
|
1364
|
+
res = safe_get(
|
|
1365
|
+
item,
|
|
1366
|
+
path,
|
|
1367
|
+
default,
|
|
1368
|
+
target_type,
|
|
1369
|
+
ignore_case,
|
|
1370
|
+
use_regex,
|
|
1371
|
+
auto_flatten,
|
|
1372
|
+
on_match,
|
|
1373
|
+
True,
|
|
1374
|
+
max_depth - 1,
|
|
1375
|
+
_seen
|
|
1376
|
+
)
|
|
1377
|
+
if res is not default:
|
|
1378
|
+
return res
|
|
1379
|
+
return default
|
|
1380
|
+
segments = path.split('.')\
|
|
1381
|
+
if isinstance(path, str)\
|
|
1382
|
+
else path
|
|
1383
|
+
current = data
|
|
1384
|
+
for key in segments:
|
|
1385
|
+
if current is None:
|
|
1386
|
+
return default
|
|
1387
|
+
try:
|
|
1388
|
+
if isinstance(current, dict):
|
|
1389
|
+
current = _find_key(
|
|
1390
|
+
current,
|
|
1391
|
+
key
|
|
1392
|
+
)
|
|
1393
|
+
elif isinstance(current, (list, tuple)):
|
|
1394
|
+
current = current[
|
|
1395
|
+
int(key)
|
|
1396
|
+
]
|
|
1397
|
+
elif hasattr(current, str(key)):
|
|
1398
|
+
current = getattr(
|
|
1399
|
+
current,
|
|
1400
|
+
str(key),
|
|
1401
|
+
default
|
|
1402
|
+
)
|
|
1403
|
+
else:
|
|
1404
|
+
return default
|
|
1405
|
+
except:
|
|
1406
|
+
return default
|
|
1407
|
+
if current is default\
|
|
1408
|
+
or current is None:
|
|
1409
|
+
return default
|
|
1410
|
+
return _run_finalize(
|
|
1411
|
+
current
|
|
1412
|
+
)
|
|
1413
|
+
deepget = deep_get = safeget = safe_get
|
|
1414
|
+
autoclass = auto_class = dataclass
|
|
1415
|
+
def auto_id(
|
|
1416
|
+
_cls=None,
|
|
1417
|
+
start: int = 1000,
|
|
1418
|
+
field: str = "__id__"
|
|
1419
|
+
) -> type:
|
|
1420
|
+
if not isinstance(start, int):
|
|
1421
|
+
start = 1000
|
|
1422
|
+
if not isinstance(field, str):
|
|
1423
|
+
field = "__id__"
|
|
1424
|
+
def decorator(cls):
|
|
1425
|
+
counters: dict[str, int] = {
|
|
1426
|
+
field: count(start),
|
|
1427
|
+
"__shanakht__": count(start)
|
|
1428
|
+
}
|
|
1429
|
+
original_init = cls.__init__
|
|
1430
|
+
@wraps(original_init)
|
|
1431
|
+
def new_init(self, *args, **kwargs):
|
|
1432
|
+
setattr(
|
|
1433
|
+
self,
|
|
1434
|
+
field,
|
|
1435
|
+
next(
|
|
1436
|
+
counters[
|
|
1437
|
+
field
|
|
1438
|
+
]
|
|
1439
|
+
)
|
|
1440
|
+
)
|
|
1441
|
+
setattr(
|
|
1442
|
+
self,
|
|
1443
|
+
"__shanakht__",
|
|
1444
|
+
next(
|
|
1445
|
+
counters[
|
|
1446
|
+
"__shanakht__"
|
|
1447
|
+
]
|
|
1448
|
+
)
|
|
1449
|
+
)
|
|
1450
|
+
original_init(
|
|
1451
|
+
self,
|
|
1452
|
+
*args,
|
|
1453
|
+
**kwargs
|
|
1454
|
+
)
|
|
1455
|
+
cls.__init__ = new_init
|
|
1456
|
+
return cls
|
|
1457
|
+
if _cls is None:
|
|
1458
|
+
return decorator
|
|
1459
|
+
return decorator(_cls)
|
|
1460
|
+
serialize = autoid = auto_id
|
|
1461
|
+
______auto_variable_count_helper______: dict = {}
|
|
1462
|
+
class AutoField:
|
|
1463
|
+
def __init__(self, start: int = 0, key:str|None=None, increment: bool=True):
|
|
1464
|
+
self.start = 0 if not isinstance(start, int) else start
|
|
1465
|
+
self.key = object() if key is None else key
|
|
1466
|
+
self.increment = increment
|
|
1467
|
+
______auto_variable_count_helper______[self.key] = start
|
|
1468
|
+
def __get__(self, instance, owner):
|
|
1469
|
+
if instance is None:
|
|
1470
|
+
return self
|
|
1471
|
+
key = (id(instance), self.key)
|
|
1472
|
+
if key not in ______auto_variable_count_helper______: ______auto_variable_count_helper______[key] = self.start
|
|
1473
|
+
value = ______auto_variable_count_helper______[key]
|
|
1474
|
+
if self.increment:
|
|
1475
|
+
______auto_variable_count_helper______[key] += 1
|
|
1476
|
+
else: ______auto_variable_count_helper______[key] -= 1
|
|
1477
|
+
return value
|
|
1478
|
+
def __call__(self):
|
|
1479
|
+
value = ______auto_variable_count_helper______[self.key]
|
|
1480
|
+
if self.increment:
|
|
1481
|
+
______auto_variable_count_helper______[self.key] += 1
|
|
1482
|
+
else: ______auto_variable_count_helper______[self.key] -= 1
|
|
1483
|
+
return value
|
|
1484
|
+
def auto_inc(start: int = 0):
|
|
1485
|
+
if not isinstance(start, int):
|
|
1486
|
+
start = 0
|
|
1487
|
+
return AutoField(start=start)
|
|
1488
|
+
def auto_dec(start: int = 0):
|
|
1489
|
+
if not isinstance(start, int):
|
|
1490
|
+
start = 0
|
|
1491
|
+
return AutoField(start, increment=False)
|
|
1492
|
+
typename = TypeT = typeT = TypeVar("T")
|
|
1493
|
+
def is_active_process(process: str) -> bool:
|
|
1494
|
+
if os.name != "nt" or not isinstance(process, str):
|
|
1495
|
+
return False
|
|
1496
|
+
process = process.strip("\"'").strip()
|
|
1497
|
+
if not process:
|
|
1498
|
+
return False
|
|
1499
|
+
if not process.lower().endswith(".exe"):
|
|
1500
|
+
process_pattern = f"{process}.exe"
|
|
1501
|
+
else:
|
|
1502
|
+
process_pattern = process
|
|
1503
|
+
try:
|
|
1504
|
+
cmd = ["tasklist", "/FI", f"IMAGENAME eq {process_pattern}", "/NH"]
|
|
1505
|
+
result = subprocess.run(
|
|
1506
|
+
cmd,
|
|
1507
|
+
stdout=subprocess.PIPE,
|
|
1508
|
+
stderr=subprocess.DEVNULL,
|
|
1509
|
+
text=True,
|
|
1510
|
+
check=False
|
|
1511
|
+
)
|
|
1512
|
+
if process_pattern.lower() not in result.stdout.lower():
|
|
1513
|
+
return False
|
|
1514
|
+
return True
|
|
1515
|
+
except Exception:
|
|
1516
|
+
return False
|
|
1517
|
+
is_running_process = is_running_app = is_active_process
|
|
1518
|
+
def run_process(
|
|
1519
|
+
command: str | list[str] | tuple[str, ...],
|
|
1520
|
+
new_window: bool = False,
|
|
1521
|
+
max: Optional[int] = None,
|
|
1522
|
+
timeout: Optional[int | float] = None,
|
|
1523
|
+
**kwargs
|
|
1524
|
+
) -> bool:
|
|
1525
|
+
if isinstance(max, int) and max == 1:
|
|
1526
|
+
if is_running_process(command):
|
|
1527
|
+
return
|
|
1528
|
+
if not command:
|
|
1529
|
+
return False
|
|
1530
|
+
if not new_window\
|
|
1531
|
+
or not isinstance(
|
|
1532
|
+
new_window,
|
|
1533
|
+
bool
|
|
1534
|
+
):
|
|
1535
|
+
new_window = any(
|
|
1536
|
+
bool(
|
|
1537
|
+
kwargs.pop(k, False)
|
|
1538
|
+
)\
|
|
1539
|
+
for k in [
|
|
1540
|
+
"dont_block",
|
|
1541
|
+
"non_blocking",
|
|
1542
|
+
"detach"
|
|
1543
|
+
]
|
|
1544
|
+
)
|
|
1545
|
+
is_shell = any(
|
|
1546
|
+
bool(
|
|
1547
|
+
kwargs.pop(k, False)
|
|
1548
|
+
)\
|
|
1549
|
+
for k in [
|
|
1550
|
+
"cmd",
|
|
1551
|
+
"internal",
|
|
1552
|
+
"shell"
|
|
1553
|
+
]
|
|
1554
|
+
)
|
|
1555
|
+
capture_output = bool(
|
|
1556
|
+
kwargs.pop(
|
|
1557
|
+
"capture_output",
|
|
1558
|
+
False
|
|
1559
|
+
)
|
|
1560
|
+
)
|
|
1561
|
+
print_output = bool(
|
|
1562
|
+
kwargs.pop(
|
|
1563
|
+
"print_output",
|
|
1564
|
+
False
|
|
1565
|
+
)
|
|
1566
|
+
)
|
|
1567
|
+
if print_output:
|
|
1568
|
+
capture_output = True
|
|
1569
|
+
as_text = bool(
|
|
1570
|
+
kwargs.get(
|
|
1571
|
+
"text",
|
|
1572
|
+
kwargs.get(
|
|
1573
|
+
"universal_newlines",
|
|
1574
|
+
False
|
|
1575
|
+
)
|
|
1576
|
+
)
|
|
1577
|
+
) or print_output
|
|
1578
|
+
kwargs["text"] = as_text
|
|
1579
|
+
kwargs["shell"] = is_shell
|
|
1580
|
+
if isinstance(command, tuple):
|
|
1581
|
+
command = list(command)
|
|
1582
|
+
if isinstance(command, str):
|
|
1583
|
+
if not is_shell\
|
|
1584
|
+
and os.name != 'nt':
|
|
1585
|
+
command = shlex.split(
|
|
1586
|
+
command,
|
|
1587
|
+
posix=True
|
|
1588
|
+
)
|
|
1589
|
+
elif isinstance(command, list)\
|
|
1590
|
+
and is_shell:
|
|
1591
|
+
if os.name == 'nt':
|
|
1592
|
+
command = subprocess\
|
|
1593
|
+
.list2cmdline(
|
|
1594
|
+
command
|
|
1595
|
+
)
|
|
1596
|
+
else:
|
|
1597
|
+
command = shlex.join(
|
|
1598
|
+
command
|
|
1599
|
+
)
|
|
1600
|
+
if os.name == 'nt':
|
|
1601
|
+
creationflags = kwargs.get("creationflags", 0)\
|
|
1602
|
+
| subprocess\
|
|
1603
|
+
.CREATE_NEW_PROCESS_GROUP
|
|
1604
|
+
kwargs["creationflags"] = creationflags
|
|
1605
|
+
empty_buf = "" if as_text else b""
|
|
1606
|
+
stdout, stderr = empty_buf, empty_buf
|
|
1607
|
+
return_code = 1
|
|
1608
|
+
try:
|
|
1609
|
+
if new_window:
|
|
1610
|
+
stdout_pipe = subprocess.PIPE\
|
|
1611
|
+
if capture_output else None
|
|
1612
|
+
stderr_pipe = subprocess.PIPE\
|
|
1613
|
+
if capture_output else None
|
|
1614
|
+
proc = subprocess.Popen(
|
|
1615
|
+
command,
|
|
1616
|
+
stdout=stdout_pipe,
|
|
1617
|
+
stderr=stderr_pipe,
|
|
1618
|
+
**kwargs
|
|
1619
|
+
)
|
|
1620
|
+
if not capture_output:
|
|
1621
|
+
timer.sleep(0.05)
|
|
1622
|
+
return proc.poll() is None or\
|
|
1623
|
+
proc.poll() == 0
|
|
1624
|
+
try:
|
|
1625
|
+
stdout, stderr = proc.communicate(
|
|
1626
|
+
timeout=timeout
|
|
1627
|
+
)
|
|
1628
|
+
return_code = proc.returncode
|
|
1629
|
+
except subprocess.TimeoutExpired:
|
|
1630
|
+
if os.name == "nt":
|
|
1631
|
+
try:
|
|
1632
|
+
proc.send_signal(
|
|
1633
|
+
signal\
|
|
1634
|
+
.CTRL_BREAK_EVENT
|
|
1635
|
+
)
|
|
1636
|
+
except Exception:
|
|
1637
|
+
proc.kill()
|
|
1638
|
+
else:
|
|
1639
|
+
proc.kill()
|
|
1640
|
+
stdout, stderr = proc\
|
|
1641
|
+
.communicate()
|
|
1642
|
+
return_code = 1
|
|
1643
|
+
else:
|
|
1644
|
+
try:
|
|
1645
|
+
proc_res = subprocess.run(
|
|
1646
|
+
command,
|
|
1647
|
+
capture_output=capture_output,
|
|
1648
|
+
timeout=timeout,
|
|
1649
|
+
**kwargs
|
|
1650
|
+
)
|
|
1651
|
+
return_code = proc_res.returncode
|
|
1652
|
+
if capture_output:
|
|
1653
|
+
stdout, stderr = proc_res.stdout, proc_res.stderr
|
|
1654
|
+
else:
|
|
1655
|
+
return return_code == 0
|
|
1656
|
+
except subprocess.TimeoutExpired as e:
|
|
1657
|
+
stdout = e.stdout\
|
|
1658
|
+
if e.stdout is not None\
|
|
1659
|
+
else empty_buf
|
|
1660
|
+
stderr = e.stderr\
|
|
1661
|
+
if e.stderr is not None\
|
|
1662
|
+
else empty_buf
|
|
1663
|
+
return_code = 1
|
|
1664
|
+
if print_output:
|
|
1665
|
+
out = stdout if stdout else stderr
|
|
1666
|
+
if out:
|
|
1667
|
+
msg = out.decode(errors="replace")\
|
|
1668
|
+
if isinstance(out, (bytes, bytearray))\
|
|
1669
|
+
else str(out)
|
|
1670
|
+
if msg.strip():
|
|
1671
|
+
print(msg.strip())
|
|
1672
|
+
return return_code == 0
|
|
1673
|
+
except Exception as e:
|
|
1674
|
+
print(f"Process execution failed, reason: {e}")
|
|
1675
|
+
return False
|
|
1676
|
+
run_command = execute_command = execute_process = run_process
|
|
1677
|
+
def kill_process(process_name: str) -> bool:
|
|
1678
|
+
process_name: str = str(process_name).strip()
|
|
1679
|
+
killed: bool = False
|
|
1680
|
+
if not process_name:
|
|
1681
|
+
return False
|
|
1682
|
+
opsys: str = platform.system().lower()
|
|
1683
|
+
try:
|
|
1684
|
+
if opsys == "windows" or os.name == "nt":
|
|
1685
|
+
if not process_name.lower().endswith(".exe"):
|
|
1686
|
+
process_name += ".exe"
|
|
1687
|
+
# need this
|
|
1688
|
+
run_process(f"taskkill /f /im {process_name}")
|
|
1689
|
+
else:
|
|
1690
|
+
run_process(f"pkill -f {process_name}")
|
|
1691
|
+
killed = True
|
|
1692
|
+
except:
|
|
1693
|
+
killed = False
|
|
1694
|
+
return killed
|
|
1695
|
+
kill_application = kill_app = kill_process
|
|
1696
|
+
def Int(x: str|int|float, base: int = 10) -> int:
|
|
1697
|
+
try:
|
|
1698
|
+
if x is None or\
|
|
1699
|
+
not isinstance(
|
|
1700
|
+
x,
|
|
1701
|
+
(str, int, float, bool)
|
|
1702
|
+
):
|
|
1703
|
+
return 0
|
|
1704
|
+
if isinstance(x, bool):
|
|
1705
|
+
return 1\
|
|
1706
|
+
if x else 0
|
|
1707
|
+
if not base or\
|
|
1708
|
+
not isinstance(base, int)\
|
|
1709
|
+
or base <= 0\
|
|
1710
|
+
or base >= Infinity:
|
|
1711
|
+
base = 10
|
|
1712
|
+
x = str(x).strip()
|
|
1713
|
+
x = replace(
|
|
1714
|
+
x,
|
|
1715
|
+
r"[^\-\.\d]",
|
|
1716
|
+
""
|
|
1717
|
+
)
|
|
1718
|
+
# NOTE: keep the dot(.), it's needed for now. keep. the. dot.
|
|
1719
|
+
# ^ allow the dot(.) to pass through, for now, so that 23.5 does NOT become 253
|
|
1720
|
+
if "." in x\
|
|
1721
|
+
and len(x) >= 2:
|
|
1722
|
+
# and later, remove it gracefully
|
|
1723
|
+
x = x.split(".")[0]
|
|
1724
|
+
return int(x, base)
|
|
1725
|
+
except (ValueError, TypeError):
|
|
1726
|
+
return 0
|
|
1727
|
+
def Flt(x: str|int|float) -> float:
|
|
1728
|
+
try:
|
|
1729
|
+
if x is None or\
|
|
1730
|
+
not isinstance(
|
|
1731
|
+
x,
|
|
1732
|
+
(str, int, float, bool)
|
|
1733
|
+
):
|
|
1734
|
+
return 0.0
|
|
1735
|
+
if isinstance(x, bool):
|
|
1736
|
+
return 1.0\
|
|
1737
|
+
if x else 0.0
|
|
1738
|
+
if isinstance(x, str):
|
|
1739
|
+
x = replace(
|
|
1740
|
+
x.strip(),
|
|
1741
|
+
r"[^e\+\-\.\d]",
|
|
1742
|
+
""
|
|
1743
|
+
)
|
|
1744
|
+
return float(x)
|
|
1745
|
+
except (ValueError, TypeError):
|
|
1746
|
+
return 0.0
|
|
1747
|
+
def is_pos(n: int|float) -> bool:
|
|
1748
|
+
"""agar number ek positive number he to kehta he `Han`,
|
|
1749
|
+
warna `Nahi`"""
|
|
1750
|
+
if not n\
|
|
1751
|
+
or not isinstance(n, (int, float)):
|
|
1752
|
+
return False
|
|
1753
|
+
return n > 0
|
|
1754
|
+
he_positive = he_pos = is_pos
|
|
1755
|
+
def is_neg(n: int|float) -> bool:
|
|
1756
|
+
"""agar number ek negative number he to kehta he `Han`,
|
|
1757
|
+
warna `Nahi`"""
|
|
1758
|
+
if not n\
|
|
1759
|
+
or not isinstance(n, (int, float)):
|
|
1760
|
+
return False
|
|
1761
|
+
return n < 0
|
|
1762
|
+
he_negative = he_neg = is_neg
|
|
1763
|
+
def is_even(n: int) -> bool:
|
|
1764
|
+
"""agar number ek even number he to kehta he `Han`,
|
|
1765
|
+
warna `Nahi`"""
|
|
1766
|
+
if not isinstance(n, int):
|
|
1767
|
+
return False
|
|
1768
|
+
# allow zero to pass through
|
|
1769
|
+
# might not seem like it,
|
|
1770
|
+
# but it does have the quality OF being even,
|
|
1771
|
+
# or odd, it even... though
|
|
1772
|
+
return n % 2 == 0
|
|
1773
|
+
he_even = is_even
|
|
1774
|
+
def is_odd(n: int) -> bool:
|
|
1775
|
+
"""agar number ek odd number he to kehta he `Han`,
|
|
1776
|
+
warna `Nahi`"""
|
|
1777
|
+
if not isinstance(n, int):
|
|
1778
|
+
return False
|
|
1779
|
+
# allow zero to pass through
|
|
1780
|
+
# might not seem like it,
|
|
1781
|
+
# but it does have the quality OF being even,
|
|
1782
|
+
# or odd, it's not odd though
|
|
1783
|
+
return n % 2 != 0
|
|
1784
|
+
he_odd = is_odd
|
|
1785
|
+
char_code = ascii_code = int_code = lambda c: ord(c[0]) if isinstance(c, str) else 0
|
|
1786
|
+
Function = Fc = Pukarne_Layak = Callable
|
|
1787
|
+
def delay(n: int, fn: Callable) -> None:
|
|
1788
|
+
"""
|
|
1789
|
+
kism<nr> `n` seconds baad kisi operation ko perform karne ke lie
|
|
1790
|
+
@param
|
|
1791
|
+
n kism<int | float>
|
|
1792
|
+
the delay in seconds
|
|
1793
|
+
@param fn
|
|
1794
|
+
fn kism<Pukarne_Layak / Function>
|
|
1795
|
+
the function to be executed after the delay
|
|
1796
|
+
@return_type
|
|
1797
|
+
kism<KoiNa|NoneType>
|
|
1798
|
+
operation perform karke koi value return nahi karta (koi_na|None)
|
|
1799
|
+
"""
|
|
1800
|
+
if not isinstance(n, (int, float)) or n <= 0:
|
|
1801
|
+
n = 1
|
|
1802
|
+
MAX_DELAY: int = int(1e5)
|
|
1803
|
+
if n > MAX_DELAY:
|
|
1804
|
+
n = MAX_DELAY
|
|
1805
|
+
# good practice
|
|
1806
|
+
if not isinstance(fn, Callable):
|
|
1807
|
+
return
|
|
1808
|
+
timed_fn: Timer = Timer(n, fn)
|
|
1809
|
+
timed_fn.start()
|
|
1810
|
+
sec, mint = 1, 60
|
|
1811
|
+
# helpers contants
|
|
1812
|
+
# so we can do delay(5*min, lambda: doSomeThing())
|
|
1813
|
+
# again, helper constants
|
|
1814
|
+
after = baad = delay
|
|
1815
|
+
def blocking_sleep(s: Number = 5) -> None:
|
|
1816
|
+
if not isinstance(s, Number):
|
|
1817
|
+
return
|
|
1818
|
+
from time import sleep
|
|
1819
|
+
sleep(s)
|
|
1820
|
+
wait = rukawat = rukaawat = blocking_sleep
|
|
1821
|
+
def get_platform() -> str:
|
|
1822
|
+
from platform import system
|
|
1823
|
+
return system()
|
|
1824
|
+
get_os = get_platform
|
|
1825
|
+
user_os = user_platform = get_platform()
|
|
1826
|
+
def try_luck(*args, default=None) -> Optional[Any]:
|
|
1827
|
+
import random
|
|
1828
|
+
high = True
|
|
1829
|
+
low = False
|
|
1830
|
+
if args:
|
|
1831
|
+
if len(args) >= 1:
|
|
1832
|
+
if isinstance(args[0], (list, tuple, set)):
|
|
1833
|
+
args = list(args[0])
|
|
1834
|
+
if len(args) >= 2:
|
|
1835
|
+
default = args[1]
|
|
1836
|
+
high = args[0]
|
|
1837
|
+
low = default
|
|
1838
|
+
return random.choice([high, low])
|
|
1839
|
+
Re = re.Re = re.compile
|
|
1840
|
+
re.repl = re.sub
|
|
1841
|
+
def th(n: Number) -> str:
|
|
1842
|
+
if not isinstance(n, Number):
|
|
1843
|
+
return "0th"
|
|
1844
|
+
n = abs(int(n))
|
|
1845
|
+
if 10 <= n % 100 <= 20:
|
|
1846
|
+
suffix = "th"
|
|
1847
|
+
else:
|
|
1848
|
+
suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
|
|
1849
|
+
return str(n) + suffix
|
|
1850
|
+
def fus(amount: Number) -> str:
|
|
1851
|
+
if amount is None or not isinstance(amount, Number):
|
|
1852
|
+
return ""
|
|
1853
|
+
amount = round(amount, 1)
|
|
1854
|
+
parts = str(amount).split('.')
|
|
1855
|
+
integer_part = '{:,}'.format(int(parts[0]))
|
|
1856
|
+
decimal_part = f".{parts[1]}" if len(parts) > 1 else ''
|
|
1857
|
+
result: str = f"{integer_part}{decimal_part}"
|
|
1858
|
+
result = re.sub(r"\.0+$", "", result)
|
|
1859
|
+
return result
|
|
1860
|
+
def fpk(amount: Number) -> str:
|
|
1861
|
+
if amount is None or not isinstance(amount, Number):
|
|
1862
|
+
return ""
|
|
1863
|
+
amount = round(amount, 1)
|
|
1864
|
+
parts = str(amount).split('.')
|
|
1865
|
+
# Indian formatting for integer part
|
|
1866
|
+
integer_part = parts[0]
|
|
1867
|
+
if len(integer_part) > 3:
|
|
1868
|
+
last_three = integer_part[-3:]
|
|
1869
|
+
rest = integer_part[:-3]
|
|
1870
|
+
rest = ','.join(reversed([rest[max(0, i-2):i] for i in range(len(rest), 0, -2)]))
|
|
1871
|
+
integer_part = f"{rest},{last_three}" if rest else last_three
|
|
1872
|
+
decimal_part = f".{parts[1]}" if len(parts) > 1 else ''
|
|
1873
|
+
format: str = f"{integer_part}{decimal_part}"
|
|
1874
|
+
# fixing a bug...
|
|
1875
|
+
result: str = format.replace("-,", "-")
|
|
1876
|
+
result = re.sub(r"\.0+$", "", result)
|
|
1877
|
+
return result
|
|
1878
|
+
athwa: float = 0.125
|
|
1879
|
+
chotha: float = 0.25
|
|
1880
|
+
adha: float = 0.5
|
|
1881
|
+
dedh: float = 1.5
|
|
1882
|
+
dhai: float = 2.5
|
|
1883
|
+
tin: int = 3
|
|
1884
|
+
chaar: int = 4
|
|
1885
|
+
ath: int = 8
|
|
1886
|
+
aath = ath
|
|
1887
|
+
def number_list_validator(args: tuple[Any]):
|
|
1888
|
+
args = list(args)
|
|
1889
|
+
if len(args) == 1 and isinstance(args[0], (list, tuple)):
|
|
1890
|
+
args = list(args[0])
|
|
1891
|
+
if not all(isinstance(arg, (int, float)) for arg in args):
|
|
1892
|
+
return []
|
|
1893
|
+
return args
|
|
1894
|
+
def mean(*args: tuple[int | float]) -> float:
|
|
1895
|
+
args = number_list_validator(args)
|
|
1896
|
+
if not args:
|
|
1897
|
+
return 0.0
|
|
1898
|
+
return float(sum(args) / len(args))
|
|
1899
|
+
avg = average = math.avg = math.average = math.mean = mean
|
|
1900
|
+
def median(*args: tuple[int | float]) -> float:
|
|
1901
|
+
args = number_list_validator(args)
|
|
1902
|
+
if not args:
|
|
1903
|
+
return 0.0
|
|
1904
|
+
args = sorted(args)
|
|
1905
|
+
mid_of_length: int = len(args) // 2
|
|
1906
|
+
if len(args) % 2 != 0:
|
|
1907
|
+
return float(args[mid_of_length])
|
|
1908
|
+
first_middle: int | float = args[mid_of_length - 1]
|
|
1909
|
+
second_middle: int | float = args[mid_of_length]
|
|
1910
|
+
return float((first_middle + second_middle) / 2)
|
|
1911
|
+
math.find_middle = math.middle_number = math.find_median = math.median = median
|
|
1912
|
+
def arithmode(*args: tuple[int | float]) -> float:
|
|
1913
|
+
args = number_list_validator(args)
|
|
1914
|
+
if not args:
|
|
1915
|
+
return 0.0
|
|
1916
|
+
most_frequent_number: int | float = Counter(args).most_common(1)[0][0]
|
|
1917
|
+
return float(most_frequent_number)
|
|
1918
|
+
math.frequent = math.most_frequent = math.mode = frequent = most_frequent = arith_mode = arithmode
|
|
1919
|
+
def arithrange(*args: tuple[int | float]) -> float:
|
|
1920
|
+
args = number_list_validator(args)
|
|
1921
|
+
if not args:
|
|
1922
|
+
return 0.0
|
|
1923
|
+
return float(max(args) - min(args))
|
|
1924
|
+
math.arith_range = math.arithrange = arith_range = arithrange
|
|
1925
|
+
def IntInput(*args, **kwargs):
|
|
1926
|
+
try:
|
|
1927
|
+
return Int(input(*args, **kwargs))
|
|
1928
|
+
except Exception:
|
|
1929
|
+
return 0
|
|
1930
|
+
def FltInput(*args, **kwargs):
|
|
1931
|
+
try:
|
|
1932
|
+
return Flt(input(*args, **kwargs))
|
|
1933
|
+
except Exception:
|
|
1934
|
+
return 0
|
|
1935
|
+
intInput, fltInput = IntInput, FltInput
|
|
1936
|
+
def flattened(lst: list[Any]) -> list[Any]:
|
|
1937
|
+
if lst is None or not isinstance(lst, list):
|
|
1938
|
+
return []
|
|
1939
|
+
out: list[Any] = []
|
|
1940
|
+
for item in lst:
|
|
1941
|
+
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
|
|
1942
|
+
out.extend(flattened(item))
|
|
1943
|
+
else:
|
|
1944
|
+
out.append(item)
|
|
1945
|
+
return out
|
|
1946
|
+
flat = flatten = flattened
|
|
1947
|
+
def clone(item: list|tuple|dict) -> list|tuple|dict:
|
|
1948
|
+
if item is None:
|
|
1949
|
+
return None
|
|
1950
|
+
return deepcopy(item)
|
|
1951
|
+
"""
|
|
1952
|
+
__KL_Py.deepcopy__
|
|
1953
|
+
|
|
1954
|
+
@param item
|
|
1955
|
+
@@type (list, tuple, dict)
|
|
1956
|
+
:: object to clone
|
|
1957
|
+
@return
|
|
1958
|
+
@@type (list, tuple, dict)
|
|
1959
|
+
:: a cloned object
|
|
1960
|
+
depending on
|
|
1961
|
+
the type passed
|
|
1962
|
+
in as the argument
|
|
1963
|
+
"""
|
|
1964
|
+
def lambai(x: Iterable) -> int:
|
|
1965
|
+
if not isinstance(x, Iterable):
|
|
1966
|
+
return 0
|
|
1967
|
+
return len(x)
|
|
1968
|
+
def barabar(x, y) -> haal:
|
|
1969
|
+
if isinstance(x, str) and isinstance(y, str):
|
|
1970
|
+
return x.lower() == y.lower()
|
|
1971
|
+
return x == y
|
|
1972
|
+
def he(x: Any, y: Any = None) -> bool:
|
|
1973
|
+
"""
|
|
1974
|
+
stricter he
|
|
1975
|
+
ONLY EXISTS TO BOOST READABILITY
|
|
1976
|
+
IN HINDGUI-ONLY (non-Klang) PROJECTS
|
|
1977
|
+
different from `barabar`
|
|
1978
|
+
which uses case-insensitivity for strings
|
|
1979
|
+
"""
|
|
1980
|
+
if x is not None and y is None:
|
|
1981
|
+
return bool(x)
|
|
1982
|
+
return x == y
|
|
1983
|
+
mojud = bool
|
|
1984
|
+
def yato(x, y) -> bool:
|
|
1985
|
+
return x or y
|
|
1986
|
+
def collect(x, *rest) -> list[list[Any], list[Any]]:
|
|
1987
|
+
if not x or not rest or len(rest) == 0 or not is_iterable(x) or not all(isinstance(item, Iterable) for item in [x, *rest]):
|
|
1988
|
+
return [[], []]
|
|
1989
|
+
args: list = [x, *rest]
|
|
1990
|
+
return list(zip(args))
|
|
1991
|
+
# wraps the old enumerate function
|
|
1992
|
+
# to avoid stack overflow
|
|
1993
|
+
# we'll need this
|
|
1994
|
+
ikhatte = collect
|
|
1995
|
+
old_enumerate = builtins.enumerate
|
|
1996
|
+
def numbered(x: str|list|tuple|dict, *args, **kwargs) -> list[list[Any], list[int]]:
|
|
1997
|
+
if not x or not isinstance(x, (str, list, tuple, dict)):
|
|
1998
|
+
return []
|
|
1999
|
+
kwargs["start"] = kwargs.pop("shuru", kwargs.pop("start", 0))
|
|
2000
|
+
enumeration_object: old_enumerate = old_enumerate(x, *args, **kwargs)
|
|
2001
|
+
if not enumeration_object:
|
|
2002
|
+
return []
|
|
2003
|
+
lst: list = list(enumeration_object)
|
|
2004
|
+
if not lst:
|
|
2005
|
+
return []
|
|
2006
|
+
return [(v, i) for i, v in lst]
|
|
2007
|
+
# WARNING: the `old_enumerate` part
|
|
2008
|
+
# is supposed to be AS/IS
|
|
2009
|
+
# this function overrides
|
|
2010
|
+
# the old enumerate function
|
|
2011
|
+
# for Klang
|
|
2012
|
+
# and replaces it with numbered
|
|
2013
|
+
# also, the swapping is a mandatory step
|
|
2014
|
+
# allowing the following syntax:
|
|
2015
|
+
# for item, i in numbered(arr):
|
|
2016
|
+
# print("{i}. {item}")
|
|
2017
|
+
enumer = numbered
|
|
2018
|
+
__old_list__ = builtins.list
|
|
2019
|
+
class Arr(__old_list__):
|
|
2020
|
+
current_type = Any
|
|
2021
|
+
length_is_final: bool = False
|
|
2022
|
+
def __init__(self, *objs, fixed: bool = False):
|
|
2023
|
+
objs = flattened(__old_list__(objs))
|
|
2024
|
+
if len(objs) > 0 and objs[0] is not None and objs[0] is not Iterable:
|
|
2025
|
+
self.current_type = type(objs[0])
|
|
2026
|
+
super().__init__()
|
|
2027
|
+
self.push(objs)
|
|
2028
|
+
filtered_lst: list = []
|
|
2029
|
+
if self.current_type is not Any:
|
|
2030
|
+
for item in self:
|
|
2031
|
+
if isinstance(item, Number) and not isinstance(item, bool) and self.current_type == str:
|
|
2032
|
+
item = Str(item)
|
|
2033
|
+
if re.search(r"\d|\b(?:True|False)\b", str(item)) and isinstance(item, (str, int, float, bool)) and self.current_type in [int, float]:
|
|
2034
|
+
if self.current_type == int:
|
|
2035
|
+
item = Int(item)
|
|
2036
|
+
else:
|
|
2037
|
+
item = Flt(item)
|
|
2038
|
+
# ^ WARNING (change not needed): refers to `Int` instead of
|
|
2039
|
+
# builtin `int`
|
|
2040
|
+
# FOR A REASON:
|
|
2041
|
+
# forced int-ification (if possible)
|
|
2042
|
+
# applying the type filter on items
|
|
2043
|
+
if type(item) != self.current_type:
|
|
2044
|
+
continue
|
|
2045
|
+
filtered_lst.append(item)
|
|
2046
|
+
self.clear()
|
|
2047
|
+
self[:] = filtered_lst
|
|
2048
|
+
if fixed:
|
|
2049
|
+
self.length_is_final = True
|
|
2050
|
+
def filter_out(self, fn):
|
|
2051
|
+
if not callable(fn):
|
|
2052
|
+
return self
|
|
2053
|
+
self[:] = [x for x in self if not fn(x)]
|
|
2054
|
+
return self
|
|
2055
|
+
def keep_if(self, fn):
|
|
2056
|
+
if not callable(fn):
|
|
2057
|
+
return self
|
|
2058
|
+
self[:] = [x for x in self if fn(x)]
|
|
2059
|
+
return self
|
|
2060
|
+
def map(self, fn):
|
|
2061
|
+
if not callable(fn):
|
|
2062
|
+
return self
|
|
2063
|
+
self[:] = [fn(x) for x in self]
|
|
2064
|
+
return self
|
|
2065
|
+
def unique(self):
|
|
2066
|
+
self[:] = __old_list__(dict.fromkeys(self))
|
|
2067
|
+
return self
|
|
2068
|
+
def has(self, x):
|
|
2069
|
+
return x in self
|
|
2070
|
+
def includes(self, x):
|
|
2071
|
+
return self.has(x)
|
|
2072
|
+
def i(self, i, default=None):
|
|
2073
|
+
if not isinstance(i, int):
|
|
2074
|
+
return self
|
|
2075
|
+
if i < 0:
|
|
2076
|
+
i = len(self) + i
|
|
2077
|
+
if 0 <= i < len(self):
|
|
2078
|
+
return self[i]
|
|
2079
|
+
return default
|
|
2080
|
+
def last(self):
|
|
2081
|
+
if self:
|
|
2082
|
+
return self[-1]
|
|
2083
|
+
return self
|
|
2084
|
+
def last_i(self, n: int = 1):
|
|
2085
|
+
if not isinstance(n, int):
|
|
2086
|
+
return self
|
|
2087
|
+
if n > 0 and n <= len(self):
|
|
2088
|
+
return self[-n]
|
|
2089
|
+
return self
|
|
2090
|
+
def nth(self, n):
|
|
2091
|
+
return self.i(n)
|
|
2092
|
+
def nth_last(self, n):
|
|
2093
|
+
return self.last_i(n)
|
|
2094
|
+
def first(self):
|
|
2095
|
+
if self:
|
|
2096
|
+
return self[0]
|
|
2097
|
+
return None
|
|
2098
|
+
def second(self):
|
|
2099
|
+
return self.i(1)
|
|
2100
|
+
def sec_last(self):
|
|
2101
|
+
return self.last_i(2)
|
|
2102
|
+
def update(self, i, x):
|
|
2103
|
+
if not isinstance(i, int):
|
|
2104
|
+
return self
|
|
2105
|
+
if i < 0:
|
|
2106
|
+
i = len(self) + i
|
|
2107
|
+
if 0 <= i < len(self):
|
|
2108
|
+
self[i] = x
|
|
2109
|
+
return self
|
|
2110
|
+
def replace(self, i, x):
|
|
2111
|
+
return self.update(i, x)
|
|
2112
|
+
def shuffle(self):
|
|
2113
|
+
if len(self) > 1:
|
|
2114
|
+
random.shuffle(self)
|
|
2115
|
+
return self
|
|
2116
|
+
def sort(self, key=None, reverse=False):
|
|
2117
|
+
if len(self) > 1:
|
|
2118
|
+
super().sort(key=key, reverse=reverse)
|
|
2119
|
+
return self
|
|
2120
|
+
def reverse(self):
|
|
2121
|
+
if len(self) > 1:
|
|
2122
|
+
super().reverse()
|
|
2123
|
+
return self
|
|
2124
|
+
def key_array(self):
|
|
2125
|
+
return __old_list__(range(len(self)))
|
|
2126
|
+
def keys(self):
|
|
2127
|
+
return self.key_array()
|
|
2128
|
+
def values(self):
|
|
2129
|
+
return __old_list__(self)
|
|
2130
|
+
def entries(self):
|
|
2131
|
+
return [self.keys(), self.values()]
|
|
2132
|
+
def slice(self, start: int = None, end: int = None):
|
|
2133
|
+
if not isinstance(start, int) or not isinstance(end, int) or start >= len(self) or end > len(self) or start == end:
|
|
2134
|
+
return self[:]
|
|
2135
|
+
return Arr(self[start:end])
|
|
2136
|
+
def slice_keep(self, x):
|
|
2137
|
+
if not isinstance(x, int) or x <= len(self) or x > len(self):
|
|
2138
|
+
return self.copy()
|
|
2139
|
+
return self.slice(0, x)
|
|
2140
|
+
def slice_right(self, x):
|
|
2141
|
+
if not isinstance(x, int):
|
|
2142
|
+
return self.copy()
|
|
2143
|
+
return self.slice(len(self) - x)
|
|
2144
|
+
def slice_end(self, x):
|
|
2145
|
+
if not isinstance(x, int):
|
|
2146
|
+
return self.copy()
|
|
2147
|
+
return self.slice(0, len(self) - x)
|
|
2148
|
+
def random(self):
|
|
2149
|
+
if self:
|
|
2150
|
+
return random.choice(self)
|
|
2151
|
+
return None
|
|
2152
|
+
def empty(self) -> Self:
|
|
2153
|
+
self.clear()
|
|
2154
|
+
return self
|
|
2155
|
+
def eq(self, other):
|
|
2156
|
+
if not isinstance(other, __old_list__):
|
|
2157
|
+
return False
|
|
2158
|
+
return self == other
|
|
2159
|
+
def compare(self, other):
|
|
2160
|
+
if not isinstance(other, __old_list__):
|
|
2161
|
+
return False
|
|
2162
|
+
intersection = Arr(set(self) & set(other))
|
|
2163
|
+
return len(intersection) > len(self) / 2
|
|
2164
|
+
def union(self, *arrays):
|
|
2165
|
+
return self.combine(*arrays)
|
|
2166
|
+
def cat(self, *arrays):
|
|
2167
|
+
return self.combine(*arrays)
|
|
2168
|
+
def concat(self, *arrays):
|
|
2169
|
+
return self.combine(*arrays)
|
|
2170
|
+
def join(self, *arrays):
|
|
2171
|
+
return self.combine(*arrays)
|
|
2172
|
+
def join_str(self, s: str = ""):
|
|
2173
|
+
return str(s).join(map(str, self))
|
|
2174
|
+
def intersection(self, *arrays):
|
|
2175
|
+
for arr in arrays:
|
|
2176
|
+
if isinstance(arr, __old_list__):
|
|
2177
|
+
self[:] = [x for x in self if x in arr]
|
|
2178
|
+
elif isinstance(arr, Arr):
|
|
2179
|
+
self[:] = [x for x in self if x in arr]
|
|
2180
|
+
return self
|
|
2181
|
+
def negative_intersection(self, *arrays):
|
|
2182
|
+
for arr in arrays:
|
|
2183
|
+
if isinstance(arr, __old_list__):
|
|
2184
|
+
self[:] = [x for x in self if x not in arr]
|
|
2185
|
+
elif isinstance(arr, Arr):
|
|
2186
|
+
self[:] = [x for x in self if x not in arr]
|
|
2187
|
+
return self
|
|
2188
|
+
def map_val(self, old_val, new_val) -> Self:
|
|
2189
|
+
for i, x in enumerate(self):
|
|
2190
|
+
if x == old_val:
|
|
2191
|
+
self[i] = new_val
|
|
2192
|
+
return self
|
|
2193
|
+
def sum(self) -> Number:
|
|
2194
|
+
if not len(self):
|
|
2195
|
+
return 0.0
|
|
2196
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2197
|
+
# this is a necessary check
|
|
2198
|
+
if not len(nums):
|
|
2199
|
+
return 0.0
|
|
2200
|
+
return sum(nums)
|
|
2201
|
+
def difference(self) -> Number:
|
|
2202
|
+
if not len(self):
|
|
2203
|
+
return 0.0
|
|
2204
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2205
|
+
# this is a necessary check
|
|
2206
|
+
if not len(nums):
|
|
2207
|
+
return 0.0
|
|
2208
|
+
diff: Number = nums[0]
|
|
2209
|
+
for i, item in old_enumerate(nums):
|
|
2210
|
+
if i == 0:
|
|
2211
|
+
continue
|
|
2212
|
+
# since we've already taken care of the first item
|
|
2213
|
+
# we don't that
|
|
2214
|
+
if item > 1e9:
|
|
2215
|
+
item = 1e9
|
|
2216
|
+
if item < 1e-9:
|
|
2217
|
+
item = 1e-9
|
|
2218
|
+
diff -= item
|
|
2219
|
+
return diff
|
|
2220
|
+
diff = difference
|
|
2221
|
+
def product(self) -> Number:
|
|
2222
|
+
if not len(self):
|
|
2223
|
+
return 0.0
|
|
2224
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2225
|
+
# this is a necessary check
|
|
2226
|
+
if not len(nums):
|
|
2227
|
+
return 0.0
|
|
2228
|
+
prd: Number = nums[0]
|
|
2229
|
+
for i, item in old_enumerate(nums):
|
|
2230
|
+
if i == 0:
|
|
2231
|
+
continue
|
|
2232
|
+
# since we've already taken care of the first item
|
|
2233
|
+
# we don't that
|
|
2234
|
+
if item > 1e9:
|
|
2235
|
+
item = 1e9
|
|
2236
|
+
if item < 1e-9:
|
|
2237
|
+
item = 1e-9
|
|
2238
|
+
prd *= item
|
|
2239
|
+
return prd
|
|
2240
|
+
prd = product
|
|
2241
|
+
def quotient(self) -> Number:
|
|
2242
|
+
if not len(self):
|
|
2243
|
+
return 0.0
|
|
2244
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2245
|
+
# this is a necessary check
|
|
2246
|
+
if not len(nums):
|
|
2247
|
+
return 0.0
|
|
2248
|
+
quo: Number = nums[0]
|
|
2249
|
+
for i, item in old_enumerate(nums):
|
|
2250
|
+
if i == 0:
|
|
2251
|
+
continue
|
|
2252
|
+
# since we've already taken care of the first item
|
|
2253
|
+
# we don't that
|
|
2254
|
+
if item == 0:
|
|
2255
|
+
item = 1
|
|
2256
|
+
if item > 1e9:
|
|
2257
|
+
item = 1e9
|
|
2258
|
+
if item < 1e-9:
|
|
2259
|
+
item = 1e-9
|
|
2260
|
+
quo /= item
|
|
2261
|
+
return quo
|
|
2262
|
+
quo = quotient
|
|
2263
|
+
def max(self) -> Number:
|
|
2264
|
+
if not len(self):
|
|
2265
|
+
return 0.0
|
|
2266
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2267
|
+
# this is a necessary check
|
|
2268
|
+
if not len(nums):
|
|
2269
|
+
return 0.0
|
|
2270
|
+
return max(nums)
|
|
2271
|
+
def min(self) -> Number:
|
|
2272
|
+
if not len(self):
|
|
2273
|
+
return 0.0
|
|
2274
|
+
nums: __old_list__[Number] = [num for num in self if num is not None and isinstance(num, Number)]
|
|
2275
|
+
# this is a necessary check
|
|
2276
|
+
if not len(nums):
|
|
2277
|
+
return 0.0
|
|
2278
|
+
return min(nums)
|
|
2279
|
+
def combine(self, *args) -> Self:
|
|
2280
|
+
if self.length_is_final:
|
|
2281
|
+
return self
|
|
2282
|
+
if not args:
|
|
2283
|
+
return self
|
|
2284
|
+
for arg in args:
|
|
2285
|
+
if isinstance(arg, tuple):
|
|
2286
|
+
arg = __old_list__(arg)
|
|
2287
|
+
# a tuple?
|
|
2288
|
+
# no thanks,
|
|
2289
|
+
# we need a list
|
|
2290
|
+
if isinstance(arg, __old_list__):
|
|
2291
|
+
arg = flatten(arg)
|
|
2292
|
+
self.extend(arg)
|
|
2293
|
+
return self
|
|
2294
|
+
else:
|
|
2295
|
+
if self.current_type is not Any:
|
|
2296
|
+
if isinstance(arg, Number) and not isinstance(arg, bool) and self.current_type == str:
|
|
2297
|
+
item = Str(arg)
|
|
2298
|
+
if re.search(r"\d|\b(?:True|False)\b", str(arg)) and isinstance(arg, (str, int, float, bool)) and self.current_type in [int, float]:
|
|
2299
|
+
if self.current_type == int:
|
|
2300
|
+
arg = Int(arg)
|
|
2301
|
+
else:
|
|
2302
|
+
arg = Flt(arg)
|
|
2303
|
+
# ^ WARNING (change not needed): refers to `Int` instead of
|
|
2304
|
+
# builtin `int`
|
|
2305
|
+
# FOR A REASON:
|
|
2306
|
+
# forced int-ification (if possible)
|
|
2307
|
+
if type(arg) != self.current_type:
|
|
2308
|
+
continue
|
|
2309
|
+
self.append(arg)
|
|
2310
|
+
return self
|
|
2311
|
+
add = push = me_dalo = combine
|
|
2312
|
+
def push_at(self, i: int, *items) -> Self:
|
|
2313
|
+
if self.length_is_final:
|
|
2314
|
+
return self
|
|
2315
|
+
if not len(items):
|
|
2316
|
+
return self
|
|
2317
|
+
if not isinstance(i, int):
|
|
2318
|
+
i = len(self)
|
|
2319
|
+
if i < 0:
|
|
2320
|
+
i = 0
|
|
2321
|
+
elif i > len(self):
|
|
2322
|
+
i = len(self)
|
|
2323
|
+
#items = flatten(__old_list__(items))
|
|
2324
|
+
items = list(items)
|
|
2325
|
+
if self.current_type is not Any:
|
|
2326
|
+
for i, item in enumerate(items):
|
|
2327
|
+
if isinstance(items[i], Number) and not isinstance(items[i], bool) and self.current_type == str:
|
|
2328
|
+
items[i] = Str(item)
|
|
2329
|
+
if re.search(r"\d|\b(?:True|False)\b", str(items[i])) and isinstance(items[i], (str, int, float, bool)) and self.current_type in [int, float]:
|
|
2330
|
+
if self.current_type == int:
|
|
2331
|
+
items[i] = Int(item)
|
|
2332
|
+
else:
|
|
2333
|
+
items[i] = Flt(item)
|
|
2334
|
+
# ^ WARNING (change not needed): refers to `Int` instead of
|
|
2335
|
+
# builtin `int`
|
|
2336
|
+
# FOR A REASON:
|
|
2337
|
+
# forced int-ification (if possible)
|
|
2338
|
+
# applying the type filter on items
|
|
2339
|
+
if type(items[i]) != self.current_type:
|
|
2340
|
+
items.pop(i)
|
|
2341
|
+
x = self[:i] + items + self[i+len(items)-1:]
|
|
2342
|
+
updated_list: __old_list__ = __old_list__(x)
|
|
2343
|
+
self.clear()
|
|
2344
|
+
self.extend(updated_list)
|
|
2345
|
+
return self
|
|
2346
|
+
def push_start(self, *items) -> Self:
|
|
2347
|
+
self.push_at(0, *items)
|
|
2348
|
+
return self
|
|
2349
|
+
pehla_dalo = ke_pehle_dalo = unshift = push_start
|
|
2350
|
+
def shift(self) -> Any|None:
|
|
2351
|
+
if self.length_is_final:
|
|
2352
|
+
return None
|
|
2353
|
+
if len(self) == 0:
|
|
2354
|
+
return None
|
|
2355
|
+
return self.pop(0)
|
|
2356
|
+
# pop the first item, "shift"ing all to the left by one bit
|
|
2357
|
+
pehla_nikalo = shift
|
|
2358
|
+
# OVERRIDE self.remove
|
|
2359
|
+
old_remove = __old_list__.remove
|
|
2360
|
+
def remove(self, *items) -> Any|None:
|
|
2361
|
+
if self.length_is_final:
|
|
2362
|
+
return None
|
|
2363
|
+
if not len(self):
|
|
2364
|
+
return None
|
|
2365
|
+
if not len(items):
|
|
2366
|
+
return super().pop()
|
|
2367
|
+
items = flatten(__old_list__(items))
|
|
2368
|
+
last_removed: Any = items[-1]
|
|
2369
|
+
for item in items:
|
|
2370
|
+
if not self.contains(item):
|
|
2371
|
+
continue
|
|
2372
|
+
self.old_remove(item)
|
|
2373
|
+
return last_removed
|
|
2374
|
+
rmv = se_nikalo = mese_nikalo = remove
|
|
2375
|
+
# OVERRIDE self.pop
|
|
2376
|
+
old_pop = __old_list__.pop
|
|
2377
|
+
def pop(self, *items) -> Any|None:
|
|
2378
|
+
if self.length_is_final:
|
|
2379
|
+
return None
|
|
2380
|
+
if not len(self):
|
|
2381
|
+
return None
|
|
2382
|
+
if not len(items):
|
|
2383
|
+
return super().pop()
|
|
2384
|
+
items = flatten(__old_list__(items))
|
|
2385
|
+
last_popped: Any = self.old_pop(items[-1])
|
|
2386
|
+
for index in items:
|
|
2387
|
+
if index >= len(self):
|
|
2388
|
+
continue
|
|
2389
|
+
if index < 0:
|
|
2390
|
+
index = len(self) - abs(index)
|
|
2391
|
+
if index < 0 or index >= len(self):
|
|
2392
|
+
continue
|
|
2393
|
+
self.old_pop(index)
|
|
2394
|
+
return last_popped
|
|
2395
|
+
def contains(self, item) -> bool:
|
|
2396
|
+
return self.count(item) > 0
|
|
2397
|
+
has = includes = me_shamil = me_mojud = contains
|
|
2398
|
+
def index_of(self, x: Any) -> int:
|
|
2399
|
+
if not self.contains(x):
|
|
2400
|
+
return -1
|
|
2401
|
+
return self.index(x)
|
|
2402
|
+
find = find_index = index_of
|
|
2403
|
+
no_of = counts_of = __old_list__.count
|
|
2404
|
+
def print_map(self):
|
|
2405
|
+
print(self)
|
|
2406
|
+
def length(self):
|
|
2407
|
+
return len(self)
|
|
2408
|
+
class numlist(list[Number]):
|
|
2409
|
+
def __init__(self, *items: Number|list[Number]):
|
|
2410
|
+
super().__init__()
|
|
2411
|
+
self.push(*items)
|
|
2412
|
+
def __add__(self, other: Number|list[Number]) -> Self:
|
|
2413
|
+
if isinstance(other, list):
|
|
2414
|
+
lst: numlist = numlist()
|
|
2415
|
+
for a, b in zip(self, other):
|
|
2416
|
+
lst.append(a+b)
|
|
2417
|
+
return lst
|
|
2418
|
+
if isinstance(other, Number):
|
|
2419
|
+
self.append(other)
|
|
2420
|
+
return self
|
|
2421
|
+
def __radd__(self, other: Number|list[Number]) -> Self:
|
|
2422
|
+
if isinstance(other, list):
|
|
2423
|
+
lst: numlist = numlist()
|
|
2424
|
+
for a, b in zip(self, other):
|
|
2425
|
+
lst.append(b+a)
|
|
2426
|
+
return lst
|
|
2427
|
+
if isinstance(other, Number):
|
|
2428
|
+
self.insert(0, other)
|
|
2429
|
+
return self
|
|
2430
|
+
def __sub__(self, other: list[Number]) -> Self:
|
|
2431
|
+
lst: numlist = numlist()
|
|
2432
|
+
for a, b in zip(self, other):
|
|
2433
|
+
lst.append(a-b)
|
|
2434
|
+
return lst
|
|
2435
|
+
def __rsub__(self, other: list[Number]) -> Self:
|
|
2436
|
+
lst: numlist = numlist()
|
|
2437
|
+
for a, b in zip(self, other):
|
|
2438
|
+
lst.append(b-a)
|
|
2439
|
+
return lst
|
|
2440
|
+
def __mul__(self, other: list[Number]) -> Self:
|
|
2441
|
+
lst: numlist = numlist()
|
|
2442
|
+
for a, b in zip(self, other):
|
|
2443
|
+
lst.append(a*b)
|
|
2444
|
+
return lst
|
|
2445
|
+
def __truediv__(self, other: list[Number]) -> Self:
|
|
2446
|
+
lst: numlist = numlist()
|
|
2447
|
+
for a, b in zip(self, other):
|
|
2448
|
+
if b == 0:
|
|
2449
|
+
b = 1
|
|
2450
|
+
lst.append(a/b)
|
|
2451
|
+
return lst
|
|
2452
|
+
def __pos__(self) -> Self:
|
|
2453
|
+
return numlist(+x for x in self)
|
|
2454
|
+
def __neg__(self) -> Self:
|
|
2455
|
+
return numlist(-x for x in self)
|
|
2456
|
+
def __abs__(self) -> Self:
|
|
2457
|
+
return numlist(abs(x) for x in self)
|
|
2458
|
+
def __pow__(self, other: list[Number]) -> Self:
|
|
2459
|
+
lst: numlist = numlist()
|
|
2460
|
+
for a, b in zip(self, other):
|
|
2461
|
+
if b == 0:
|
|
2462
|
+
b = 1
|
|
2463
|
+
lst.append(a ** b)
|
|
2464
|
+
return lst
|
|
2465
|
+
def __gt__(self, other: list[Number]) -> bool:
|
|
2466
|
+
return all(a > b for a, b in zip(self, other))
|
|
2467
|
+
def __lt__(self, other: list[Number]) -> bool:
|
|
2468
|
+
return all(a < b for a, b in zip(self, other))
|
|
2469
|
+
def __ge__(self, other: list[Number]) -> bool:
|
|
2470
|
+
return all(a >= b for a, b in zip(self, other))
|
|
2471
|
+
def __le__(self, other: list[Number]) -> bool:
|
|
2472
|
+
return all(a <= b for a, b in zip(self, other))
|
|
2473
|
+
def __eq__(self, other: list[Number]) -> bool:
|
|
2474
|
+
return all(a == b for a, b in zip(self, other))
|
|
2475
|
+
def __ne__(self, other: list[Number]) -> bool:
|
|
2476
|
+
return not all(a == b for a, b in zip(self, other))
|
|
2477
|
+
def __str__(self) -> str:
|
|
2478
|
+
return f"numlist([{', '.join(map(str, self))}])"
|
|
2479
|
+
def __repr__(self) -> str:
|
|
2480
|
+
return f"numlist([{', '.join(map(repr, self))}])"
|
|
2481
|
+
def sum(self) -> Number:
|
|
2482
|
+
if not len(self):
|
|
2483
|
+
return 0
|
|
2484
|
+
return sum(self)
|
|
2485
|
+
def difference(self) -> Number:
|
|
2486
|
+
if not len(self):
|
|
2487
|
+
return 0
|
|
2488
|
+
diff: Number = self[0]
|
|
2489
|
+
for i, item in old_enumerate(self):
|
|
2490
|
+
if i == 0:
|
|
2491
|
+
continue
|
|
2492
|
+
# since we've already taken care of the first item
|
|
2493
|
+
# we don't that
|
|
2494
|
+
if item > 1e9:
|
|
2495
|
+
item = 1e9
|
|
2496
|
+
if item < 1e-9:
|
|
2497
|
+
item = 1e-9
|
|
2498
|
+
diff -= item
|
|
2499
|
+
return diff
|
|
2500
|
+
diff = difference
|
|
2501
|
+
def product(self) -> Number:
|
|
2502
|
+
if not len(self):
|
|
2503
|
+
return 0
|
|
2504
|
+
prd: Number = self[0]
|
|
2505
|
+
for i, item in old_enumerate(self):
|
|
2506
|
+
if i == 0:
|
|
2507
|
+
continue
|
|
2508
|
+
# since we've already taken care of the first item
|
|
2509
|
+
# we don't that
|
|
2510
|
+
if item > 1e9:
|
|
2511
|
+
item = 1e9
|
|
2512
|
+
if item < 1e-9:
|
|
2513
|
+
item = 1e-9
|
|
2514
|
+
prd *= item
|
|
2515
|
+
return prd
|
|
2516
|
+
prd = product
|
|
2517
|
+
def quotient(self) -> Number:
|
|
2518
|
+
if not len(self):
|
|
2519
|
+
return 0
|
|
2520
|
+
quo: Number = self[0]
|
|
2521
|
+
for i, item in old_enumerate(self):
|
|
2522
|
+
if i == 0:
|
|
2523
|
+
continue
|
|
2524
|
+
# since we've already taken care of the first item
|
|
2525
|
+
# we don't that
|
|
2526
|
+
if item == 0:
|
|
2527
|
+
item = 1
|
|
2528
|
+
if item > 1e9:
|
|
2529
|
+
item = 1e9
|
|
2530
|
+
if item < 1e-9:
|
|
2531
|
+
item = 1e-9
|
|
2532
|
+
quo /= item
|
|
2533
|
+
return quo
|
|
2534
|
+
quo = quotient
|
|
2535
|
+
def max(self) -> Number:
|
|
2536
|
+
if not len(self):
|
|
2537
|
+
return 0
|
|
2538
|
+
return max(self)
|
|
2539
|
+
def min(self) -> Number:
|
|
2540
|
+
if not len(self):
|
|
2541
|
+
return 0
|
|
2542
|
+
return min(self)
|
|
2543
|
+
def combine(self, *args: list[Number]) -> Self:
|
|
2544
|
+
if not args:
|
|
2545
|
+
return self
|
|
2546
|
+
for arg in args:
|
|
2547
|
+
if not isinstance(arg, (Number, list)):
|
|
2548
|
+
continue
|
|
2549
|
+
if (isinstance(arg, list) and not all(isinstance(item, Number) for item in arg)):
|
|
2550
|
+
# if it's neither of the supported types
|
|
2551
|
+
# don't push anything
|
|
2552
|
+
continue
|
|
2553
|
+
if isinstance(arg, tuple):
|
|
2554
|
+
arg = list(arg)
|
|
2555
|
+
# a tuple?
|
|
2556
|
+
# no thanks,
|
|
2557
|
+
# we need a list
|
|
2558
|
+
if isinstance(arg, list):
|
|
2559
|
+
self.extend(arg)
|
|
2560
|
+
else:
|
|
2561
|
+
self.append(arg)
|
|
2562
|
+
return self
|
|
2563
|
+
add = push = me_dalo = combine
|
|
2564
|
+
def push_at(self, i: int, *items) -> Self:
|
|
2565
|
+
if not len(items) or not all(isinstance(item, Number) for item in items):
|
|
2566
|
+
return self
|
|
2567
|
+
if not isinstance(i, int):
|
|
2568
|
+
i = len(self)
|
|
2569
|
+
if i < 0:
|
|
2570
|
+
i = 0
|
|
2571
|
+
elif i > len(self):
|
|
2572
|
+
i = len(self)
|
|
2573
|
+
items = flatten(list(items))
|
|
2574
|
+
x = self[:i] + list(items) + self[i+len(items)-1:]
|
|
2575
|
+
updated_list: numlist = numlist(x)
|
|
2576
|
+
self.clear()
|
|
2577
|
+
self.extend(updated_list)
|
|
2578
|
+
return self
|
|
2579
|
+
def push_start(self, *items) -> Self:
|
|
2580
|
+
self.push_at(0, *items)
|
|
2581
|
+
return self
|
|
2582
|
+
unshift = push_start
|
|
2583
|
+
def shift(self) -> Number:
|
|
2584
|
+
if len(self) == 0:
|
|
2585
|
+
return 0
|
|
2586
|
+
return self.pop(0)
|
|
2587
|
+
# OVERRIDE self.remove
|
|
2588
|
+
old_remove = list[Number].remove
|
|
2589
|
+
def remove(self, *items: list[Number]) -> Number:
|
|
2590
|
+
if not len(self) or not all(isinstance(item, (Number, list)) for item in items if item is not None):
|
|
2591
|
+
return 0
|
|
2592
|
+
if not len(items):
|
|
2593
|
+
return super().pop()
|
|
2594
|
+
items = flatten(list(items))
|
|
2595
|
+
last_removed: Number = items[-1]
|
|
2596
|
+
for item in items:
|
|
2597
|
+
if not self.contains(item):
|
|
2598
|
+
continue
|
|
2599
|
+
self.old_remove(item)
|
|
2600
|
+
return last_removed
|
|
2601
|
+
rmv = se_nikalo = remove
|
|
2602
|
+
# OVERRIDE self.pop
|
|
2603
|
+
old_pop = list[Number].pop
|
|
2604
|
+
def pop(self, *items: list[Number]) -> Number:
|
|
2605
|
+
if not len(self) or not all(isinstance(item, (Number, list)) for item in items if item is not None):
|
|
2606
|
+
return 0
|
|
2607
|
+
if not len(items):
|
|
2608
|
+
return super().pop()
|
|
2609
|
+
items = flatten(list(items))
|
|
2610
|
+
last_popped: Number = self.old_pop(items[-1])
|
|
2611
|
+
for index in items:
|
|
2612
|
+
if index >= len(self):
|
|
2613
|
+
continue
|
|
2614
|
+
if index < 0:
|
|
2615
|
+
index = len(self) - abs(index)
|
|
2616
|
+
if index < 0 or index >= len(self):
|
|
2617
|
+
continue
|
|
2618
|
+
self.old_pop(index)
|
|
2619
|
+
return last_popped
|
|
2620
|
+
#def pop_at
|
|
2621
|
+
def contains(self, item) -> bool:
|
|
2622
|
+
return self.count(item) > 0
|
|
2623
|
+
has = includes = me_mojud = contains
|
|
2624
|
+
def index_of(self, x: Number) -> int:
|
|
2625
|
+
if not isinstance(x, Number) or not self.contains(x):
|
|
2626
|
+
return -1
|
|
2627
|
+
return self.index(x)
|
|
2628
|
+
find = find_index = index_of
|
|
2629
|
+
no_of = counts_of = list[Number].count
|
|
2630
|
+
"""
|
|
2631
|
+
nlist: numlist = numlist([2, 0, 5])
|
|
2632
|
+
print(nlist.pop(0, -2))
|
|
2633
|
+
print(nlist.quo())
|
|
2634
|
+
print(nlist.find(1))
|
|
2635
|
+
print(nlist)
|
|
2636
|
+
"""
|
|
2637
|
+
num_list = numlist
|
|
2638
|
+
class intlist(list[int]):
|
|
2639
|
+
def __init__(self, *items: int):
|
|
2640
|
+
super().__init__(items)
|
|
2641
|
+
def __add__(self, other: list[int]) -> Self:
|
|
2642
|
+
lst: intlist = intlist()
|
|
2643
|
+
for a, b in zip(self, other):
|
|
2644
|
+
lst.append(Int(a)+Int(b))
|
|
2645
|
+
return lst
|
|
2646
|
+
def __radd__(self, other: list[int]) -> Self:
|
|
2647
|
+
lst: intlist = intlist()
|
|
2648
|
+
for a, b in zip(self, other):
|
|
2649
|
+
lst.append(Int(b)+Int(a))
|
|
2650
|
+
return lst
|
|
2651
|
+
def __sub__(self, other: list[int]) -> Self:
|
|
2652
|
+
lst: intlist = intlist()
|
|
2653
|
+
for a, b in zip(self, other):
|
|
2654
|
+
lst.append(Int(a)-Int(b))
|
|
2655
|
+
return lst
|
|
2656
|
+
def __rsub__(self, other: list[int]) -> Self:
|
|
2657
|
+
lst: intlist = intlist()
|
|
2658
|
+
for a, b in zip(self, other):
|
|
2659
|
+
lst.append(Int(b)-Int(a))
|
|
2660
|
+
return lst
|
|
2661
|
+
def __mul__(self, other: list[int]) -> Self:
|
|
2662
|
+
lst: intlist = intlist()
|
|
2663
|
+
for a, b in zip(self, other):
|
|
2664
|
+
lst.append(Int(a)*Int(b))
|
|
2665
|
+
return lst
|
|
2666
|
+
def __truediv__(self, other: list[int]) -> Self:
|
|
2667
|
+
lst: intlist = intlist()
|
|
2668
|
+
for a, b in zip(self, other):
|
|
2669
|
+
if b == 0:
|
|
2670
|
+
b = 1
|
|
2671
|
+
lst.append(Int(a)/Int(b))
|
|
2672
|
+
return lst
|
|
2673
|
+
def __pos__(self) -> Self:
|
|
2674
|
+
return intlist(Int(+x) for x in self)
|
|
2675
|
+
def __neg__(self) -> Self:
|
|
2676
|
+
return intlist(Int(-x) for x in self)
|
|
2677
|
+
def __abs__(self) -> Self:
|
|
2678
|
+
return intlist(Int(abs(x)) for x in self)
|
|
2679
|
+
def __pow__(self, other: list[int]) -> Self:
|
|
2680
|
+
lst: intlist = intlist()
|
|
2681
|
+
for a, b in zip(self, other):
|
|
2682
|
+
if b == 0:
|
|
2683
|
+
b = 1
|
|
2684
|
+
lst.append(Int(a) ** Int(b))
|
|
2685
|
+
return lst
|
|
2686
|
+
def __gt__(self, other: list[int]) -> bool:
|
|
2687
|
+
return all(Int(a) > Int(b) for a, b in zip(self, other))
|
|
2688
|
+
def __lt__(self, other: list[int]) -> bool:
|
|
2689
|
+
return all(Int(a) < Int(b) for a, b in zip(self, other))
|
|
2690
|
+
def __ge__(self, other: list[int]) -> bool:
|
|
2691
|
+
return all(Int(a) >= Int(b) for a, b in zip(self, other))
|
|
2692
|
+
def __le__(self, other: list[int]) -> bool:
|
|
2693
|
+
return all(Int(a) <= Int(b) for a, b in zip(self, other))
|
|
2694
|
+
def __eq__(self, other: list[int]) -> bool:
|
|
2695
|
+
return all(Int(a) == Int(b) for a, b in zip(self, other))
|
|
2696
|
+
def __ne__(self, other: list[int]) -> bool:
|
|
2697
|
+
return not all(Int(a) == Int(b) for a, b in zip(self, other))
|
|
2698
|
+
def __str__(self) -> str:
|
|
2699
|
+
return f"intlist([{', '.join(map(str, self))}])"
|
|
2700
|
+
def __repr__(self) -> str:
|
|
2701
|
+
return f"intlist([{', '.join(map(repr, self))}])"
|
|
2702
|
+
int_list = intlist
|
|
2703
|
+
class fltlist(list[float]):
|
|
2704
|
+
def __init__(self, *items: int):
|
|
2705
|
+
super().__init__(items)
|
|
2706
|
+
def __add__(self, other: list[float]) -> Self:
|
|
2707
|
+
lst: fltlist = fltlist()
|
|
2708
|
+
for a, b in zip(self, other):
|
|
2709
|
+
lst.append(Flt(a)+Flt(b))
|
|
2710
|
+
return lst
|
|
2711
|
+
def __radd__(self, other: list[float]) -> Self:
|
|
2712
|
+
lst: fltlist = fltlist()
|
|
2713
|
+
for a, b in zip(self, other):
|
|
2714
|
+
lst.append(Flt(b)+Flt(a))
|
|
2715
|
+
return lst
|
|
2716
|
+
def __sub__(self, other: list[float]) -> Self:
|
|
2717
|
+
lst: fltlist = fltlist()
|
|
2718
|
+
for a, b in zip(self, other):
|
|
2719
|
+
lst.append(Flt(a)-Flt(b))
|
|
2720
|
+
return lst
|
|
2721
|
+
def __rsub__(self, other: list[float]) -> Self:
|
|
2722
|
+
lst: fltlist = fltlist()
|
|
2723
|
+
for a, b in zip(self, other):
|
|
2724
|
+
lst.append(Flt(b)-Flt(a))
|
|
2725
|
+
return lst
|
|
2726
|
+
def __mul__(self, other: list[float]) -> Self:
|
|
2727
|
+
lst: fltlist = fltlist()
|
|
2728
|
+
for a, b in zip(self, other):
|
|
2729
|
+
lst.append(Flt(a)*Flt(b))
|
|
2730
|
+
return lst
|
|
2731
|
+
def __truediv__(self, other: list[float]) -> Self:
|
|
2732
|
+
lst: fltlist = fltlist()
|
|
2733
|
+
for a, b in zip(self, other):
|
|
2734
|
+
if b == 0:
|
|
2735
|
+
b = 1
|
|
2736
|
+
lst.append(Flt(a)/Flt(b))
|
|
2737
|
+
return lst
|
|
2738
|
+
def __pos__(self) -> Self:
|
|
2739
|
+
return fltlist(Flt(+x) for x in self)
|
|
2740
|
+
def __neg__(self) -> Self:
|
|
2741
|
+
return fltlist(Flt(-x) for x in self)
|
|
2742
|
+
def __abs__(self) -> Self:
|
|
2743
|
+
return fltlist(Flt(abs(x)) for x in self)
|
|
2744
|
+
def __pow__(self, other: list[float]) -> Self:
|
|
2745
|
+
lst: fltlist = fltlist()
|
|
2746
|
+
for a, b in zip(self, other):
|
|
2747
|
+
if b == 0:
|
|
2748
|
+
b = 1
|
|
2749
|
+
lst.append(Flt(a) ** Flt(b))
|
|
2750
|
+
return lst
|
|
2751
|
+
def __gt__(self, other: list[float]) -> bool:
|
|
2752
|
+
return all(Flt(a) > Flt(b) for a, b in zip(self, other))
|
|
2753
|
+
def __lt__(self, other: list[float]) -> bool:
|
|
2754
|
+
return all(Flt(a) < Flt(b) for a, b in zip(self, other))
|
|
2755
|
+
def __ge__(self, other: list[float]) -> bool:
|
|
2756
|
+
return all(Flt(a) >= Flt(b) for a, b in zip(self, other))
|
|
2757
|
+
def __le__(self, other: list[float]) -> bool:
|
|
2758
|
+
return all(Flt(a) <= Flt(b) for a, b in zip(self, other))
|
|
2759
|
+
def __eq__(self, other: list[float]) -> bool:
|
|
2760
|
+
return all(Flt(a) == Flt(b) for a, b in zip(self, other))
|
|
2761
|
+
def __ne__(self, other: list[float]) -> bool:
|
|
2762
|
+
return not all(Flt(a) == Flt(b) for a, b in zip(self, other))
|
|
2763
|
+
def __str__(self) -> str:
|
|
2764
|
+
return f"fltlist([{', '.join(map(str, self))}])"
|
|
2765
|
+
def __repr__(self) -> str:
|
|
2766
|
+
return f"fltlist([{', '.join(map(repr, self))}])"
|
|
2767
|
+
flt_list = fltlist
|
|
2768
|
+
# preserve the sequence
|
|
2769
|
+
T: TypeVar = TypeVar('T')
|
|
2770
|
+
class Stack[T]:
|
|
2771
|
+
def __init__(self, *items: T):
|
|
2772
|
+
self.array: list[T] = []
|
|
2773
|
+
self.length: int = -1
|
|
2774
|
+
if len(items) != 0:
|
|
2775
|
+
for item in items:
|
|
2776
|
+
self.push(item)
|
|
2777
|
+
def push(self, item: T) -> Self:
|
|
2778
|
+
self.array.append(item)
|
|
2779
|
+
self.length += 1
|
|
2780
|
+
return self
|
|
2781
|
+
def pop(self) -> Optional[T]:
|
|
2782
|
+
if self.length == -1:
|
|
2783
|
+
return None
|
|
2784
|
+
popped: T = self.array[self.length]
|
|
2785
|
+
self.length -= 1
|
|
2786
|
+
return popped
|
|
2787
|
+
def top(self) -> Optional[T]:
|
|
2788
|
+
if self.length == -1:
|
|
2789
|
+
return None
|
|
2790
|
+
return self.array[self.length]
|
|
2791
|
+
def len(self) -> int:
|
|
2792
|
+
return self.length + 1
|
|
2793
|
+
def size(self) -> int:
|
|
2794
|
+
return self.len()
|
|
2795
|
+
def __len__(self) -> int:
|
|
2796
|
+
return self.len()
|
|
2797
|
+
def __str__(self) -> str:
|
|
2798
|
+
return str(self.array)
|
|
2799
|
+
def is_valid_regex(text: str) -> bool:
|
|
2800
|
+
if not isinstance(text, str):
|
|
2801
|
+
return False
|
|
2802
|
+
try:
|
|
2803
|
+
re.compile(text)
|
|
2804
|
+
return True
|
|
2805
|
+
except re.error:
|
|
2806
|
+
return False
|
|
2807
|
+
is_valid_re = he_valid_regex = he_valid_re = is_valid_regex
|
|
2808
|
+
def escape_if_not_valid_regex(text: str) -> str:
|
|
2809
|
+
if not isinstance(text, str):
|
|
2810
|
+
return ""
|
|
2811
|
+
escaped_text: str = re.escape(
|
|
2812
|
+
text
|
|
2813
|
+
)
|
|
2814
|
+
if not is_valid_regex(text):
|
|
2815
|
+
return escaped_text
|
|
2816
|
+
return text
|
|
2817
|
+
escape_if_not_valid_re = escape_if_not_valid_regex
|
|
2818
|
+
floor_get = floor_key = near_key = close_get = near_get
|
|
2819
|
+
class obj(dict):
|
|
2820
|
+
def __init__(self, *args, **kwargs):
|
|
2821
|
+
super().__init__(*args, **kwargs)
|
|
2822
|
+
self._convert_nested_dicts(self)
|
|
2823
|
+
def _convert_nested_dicts(self, object):
|
|
2824
|
+
if isinstance(object, dict):
|
|
2825
|
+
for k, v in object.items():
|
|
2826
|
+
if isinstance(v, dict):
|
|
2827
|
+
object[k] = obj(v)
|
|
2828
|
+
elif isinstance(v, (list, tuple)):
|
|
2829
|
+
object[k] = self._convert_nested_collections(v)
|
|
2830
|
+
elif isinstance(object, (list, tuple)):
|
|
2831
|
+
return self._convert_nested_collections(object)
|
|
2832
|
+
return object
|
|
2833
|
+
def _convert_nested_collections(self, collection):
|
|
2834
|
+
converted_collection = []
|
|
2835
|
+
for item in collection:
|
|
2836
|
+
if isinstance(item, dict):
|
|
2837
|
+
converted_collection.append(obj(item))
|
|
2838
|
+
elif isinstance(item, (list, tuple)):
|
|
2839
|
+
converted_collection.append(self._convert_nested_collections(item))
|
|
2840
|
+
else:
|
|
2841
|
+
converted_collection.append(item)
|
|
2842
|
+
return type(collection)(converted_collection)
|
|
2843
|
+
floor_get = floor_key = near_key = close_get = near_get = lambda self, k, default=None: globals().get("floor_get", None)(self, k, default) if callable(globals().get("floor_get", None)) else None
|
|
2844
|
+
def __call__(self, key, default = None, *args, **kwargs):
|
|
2845
|
+
return safe_get(
|
|
2846
|
+
self,
|
|
2847
|
+
path=key,
|
|
2848
|
+
default=default,
|
|
2849
|
+
*args,
|
|
2850
|
+
**kwargs
|
|
2851
|
+
)
|
|
2852
|
+
def __getitem__(self, key) -> Any:
|
|
2853
|
+
default = None
|
|
2854
|
+
if isinstance(key, (list, tuple, set))\
|
|
2855
|
+
and len(key) >= 2:
|
|
2856
|
+
key, default = key[0], key[1]
|
|
2857
|
+
if not all(
|
|
2858
|
+
isinstance(
|
|
2859
|
+
k,
|
|
2860
|
+
(str, int, float)
|
|
2861
|
+
)\
|
|
2862
|
+
for k in self.keys()
|
|
2863
|
+
):
|
|
2864
|
+
return default
|
|
2865
|
+
if not isinstance(
|
|
2866
|
+
key,
|
|
2867
|
+
(str, int, float)
|
|
2868
|
+
):
|
|
2869
|
+
return default
|
|
2870
|
+
key_lower = key.lower()\
|
|
2871
|
+
if isinstance(key, str)\
|
|
2872
|
+
else int(key)
|
|
2873
|
+
d_lower : dict = {
|
|
2874
|
+
(k.lower()\
|
|
2875
|
+
if type(k) == str\
|
|
2876
|
+
else int(k))\
|
|
2877
|
+
: v\
|
|
2878
|
+
for k, v\
|
|
2879
|
+
in self.items()
|
|
2880
|
+
}
|
|
2881
|
+
try:
|
|
2882
|
+
if isinstance(key_lower, str):
|
|
2883
|
+
if not any(
|
|
2884
|
+
k.startswith(key_lower)\
|
|
2885
|
+
for k in d_lower\
|
|
2886
|
+
if isinstance(k, str)
|
|
2887
|
+
):
|
|
2888
|
+
return default
|
|
2889
|
+
for k in d_lower:
|
|
2890
|
+
if isinstance(k, str)\
|
|
2891
|
+
and k.startswith(key_lower):
|
|
2892
|
+
return d_lower[k]
|
|
2893
|
+
elif key_lower not in d_lower:
|
|
2894
|
+
return default
|
|
2895
|
+
return d_lower[key_lower]
|
|
2896
|
+
except Exception as e:
|
|
2897
|
+
print(e)
|
|
2898
|
+
if key not in self:
|
|
2899
|
+
return default
|
|
2900
|
+
return super().__getitem__(key)
|
|
2901
|
+
ka = ki = ke = mese = __getattr__ = __call__
|
|
2902
|
+
def __setattr__(self, key, value) -> None:
|
|
2903
|
+
if isinstance(value, dict):
|
|
2904
|
+
self[key] = obj(value)
|
|
2905
|
+
elif isinstance(value, (list, tuple)):
|
|
2906
|
+
self[key] = self._convert_nested_collections(
|
|
2907
|
+
value
|
|
2908
|
+
)
|
|
2909
|
+
else:
|
|
2910
|
+
self[key] = value
|
|
2911
|
+
def __setitem__(self, key, value) -> None:
|
|
2912
|
+
if isinstance(value, dict):
|
|
2913
|
+
super().__setitem__(
|
|
2914
|
+
key,
|
|
2915
|
+
obj(value)
|
|
2916
|
+
)
|
|
2917
|
+
elif isinstance(value, (list, tuple)):
|
|
2918
|
+
super().__setitem__(
|
|
2919
|
+
key,
|
|
2920
|
+
self.\
|
|
2921
|
+
_convert_nested_collections(
|
|
2922
|
+
value
|
|
2923
|
+
)
|
|
2924
|
+
)
|
|
2925
|
+
else:
|
|
2926
|
+
super().__setitem__(
|
|
2927
|
+
key,
|
|
2928
|
+
value
|
|
2929
|
+
)
|
|
2930
|
+
def keys(self) -> list[Union[str, int, float]]:
|
|
2931
|
+
return list(
|
|
2932
|
+
super()\
|
|
2933
|
+
.keys()
|
|
2934
|
+
)
|
|
2935
|
+
def values(self) -> list[Any]:
|
|
2936
|
+
return list(
|
|
2937
|
+
super()\
|
|
2938
|
+
.values()
|
|
2939
|
+
)
|
|
2940
|
+
def entries(self) -> list[list]:
|
|
2941
|
+
return list(
|
|
2942
|
+
super()\
|
|
2943
|
+
.items()
|
|
2944
|
+
)
|
|
2945
|
+
# allows obj($x=$valueForX, $y=$valueForY)
|
|
2946
|
+
o = Obj = obj
|
|
2947
|
+
# for older dictionaries
|
|
2948
|
+
def keys(dictionary: dict) -> list:
|
|
2949
|
+
if not isinstance(dictionary, dict):
|
|
2950
|
+
return []
|
|
2951
|
+
return list(
|
|
2952
|
+
dictionary.keys()
|
|
2953
|
+
)
|
|
2954
|
+
def values(dictionary: dict) -> list:
|
|
2955
|
+
if not isinstance(dictionary, dict):
|
|
2956
|
+
return []
|
|
2957
|
+
return list(
|
|
2958
|
+
dictionary.values()
|
|
2959
|
+
)
|
|
2960
|
+
def entries(dictionary: dict) -> list:
|
|
2961
|
+
if not isinstance(dictionary, dict):
|
|
2962
|
+
return []
|
|
2963
|
+
return list(
|
|
2964
|
+
dictionary.items()
|
|
2965
|
+
)
|
|
2966
|
+
get_keys = keys_of = keys
|
|
2967
|
+
get_values = values_of = values
|
|
2968
|
+
get_entries = entries_of = entries
|
|
2969
|
+
def remove_duplicates(lst: list) -> list:
|
|
2970
|
+
if not lst or not isinstance(lst, list):
|
|
2971
|
+
return []
|
|
2972
|
+
return list(dict.fromkeys(lst).keys())
|
|
2973
|
+
def swap_keys(_obj: dict[Any, Any]) -> dict[Any, Any]:
|
|
2974
|
+
if not isinstance(_obj, Iterable):
|
|
2975
|
+
return {}
|
|
2976
|
+
return {v: k for k, v in _obj.items()}
|
|
2977
|
+
def Count(itrbl: Iterable) -> dict[int, Any]:
|
|
2978
|
+
if not isinstance(itrbl, Iterable):
|
|
2979
|
+
return {}
|
|
2980
|
+
counted: dict[int, Any] = {}
|
|
2981
|
+
for key in itrbl:
|
|
2982
|
+
counted[key] = counted.get(key, 0) + 1
|
|
2983
|
+
counted = swap_keys(counted)
|
|
2984
|
+
return counted
|
|
2985
|
+
count_occur = Count
|
|
2986
|
+
# ^DIFFERENT FROM collections.count
|
|
2987
|
+
def get_local_declarations() -> obj:
|
|
2988
|
+
"""
|
|
2989
|
+
@return
|
|
2990
|
+
<dict>
|
|
2991
|
+
::a dictionary holding all the local variables, (sub)classes (of classes), and the functions of the local scope of a class/function
|
|
2992
|
+
"""
|
|
2993
|
+
[variables, classes, functions] = [{}, {}, {}]
|
|
2994
|
+
frame = currentframe().f_back
|
|
2995
|
+
for name, _obj in frame.f_locals.items():
|
|
2996
|
+
# Exclude built-in names and imported modules
|
|
2997
|
+
if not name.startswith('__'):
|
|
2998
|
+
if isfunction(_obj):
|
|
2999
|
+
functions[name] = _obj
|
|
3000
|
+
elif isclass(_obj):
|
|
3001
|
+
classes[name] = _obj
|
|
3002
|
+
# For variables, we can assume anything else that's not a function or class
|
|
3003
|
+
# and is user-defined in this module is a variable.
|
|
3004
|
+
# This is a simplification; more robust checks might be needed for complex cases.
|
|
3005
|
+
elif not ismodule(_obj): # Exclude imported modules
|
|
3006
|
+
variables[name] = _obj
|
|
3007
|
+
return o(variables=variables, classes=classes, functions=functions)
|
|
3008
|
+
def get_global_declarations() -> obj:
|
|
3009
|
+
"""
|
|
3010
|
+
@return
|
|
3011
|
+
<dict>
|
|
3012
|
+
::a dictionary holding all the local variables, (sub)classes (of classes), and the functions of the local scope of a class/function
|
|
3013
|
+
"""
|
|
3014
|
+
[variables, classes, functions] = [{}, {}, {}]
|
|
3015
|
+
for name, _obj in globals().items():
|
|
3016
|
+
# Exclude built-in names and imported modules
|
|
3017
|
+
if not name.startswith('__') and getmodule(_obj) is sys.modules[__name__]:
|
|
3018
|
+
if isfunction(_obj):
|
|
3019
|
+
functions[name] = _obj
|
|
3020
|
+
elif isclass(_obj):
|
|
3021
|
+
classes[name] = _obj
|
|
3022
|
+
# For variables, we can assume anything else that's not a function or class
|
|
3023
|
+
# and is user-defined in this module is a variable.
|
|
3024
|
+
# This is a simplification; more robust checks might be needed for complex cases.
|
|
3025
|
+
elif not ismodule(_obj): # Exclude imported modules
|
|
3026
|
+
variables[name] = _obj
|
|
3027
|
+
return o(variables=variables, classes=classes, functions=functions)
|
|
3028
|
+
Yes = Ha = Han = true = True
|
|
3029
|
+
No = Na = Nahi = false = False
|
|
3030
|
+
none: NoneType = None
|
|
3031
|
+
null = none
|
|
3032
|
+
sort = lambda x: sorted(x) if isinstance(x, Iterable) else []
|
|
3033
|
+
reverse_sort = sort_reverse = lambda x: sorted(x, reverse=True) if isinstance(x, Iterable) else []
|
|
3034
|
+
def sort_mutate(x) -> str | list | tuple:
|
|
3035
|
+
if type(x) not in (str, list, tuple):
|
|
3036
|
+
return x
|
|
3037
|
+
was_a_string: bool = False
|
|
3038
|
+
was_a_tuple: bool = False
|
|
3039
|
+
if isinstance(x, str):
|
|
3040
|
+
x = list(x)
|
|
3041
|
+
was_a_string = True
|
|
3042
|
+
elif isinstance(x, tuple):
|
|
3043
|
+
x = list(x)
|
|
3044
|
+
was_a_tuple = True
|
|
3045
|
+
x.sort()
|
|
3046
|
+
# ^ return None after sorting
|
|
3047
|
+
# let's forcibly return the final x
|
|
3048
|
+
if was_a_string:
|
|
3049
|
+
x = "".join(str(item) for item in x)
|
|
3050
|
+
elif was_a_tuple:
|
|
3051
|
+
x = tuple(x)
|
|
3052
|
+
return x
|
|
3053
|
+
mutate_sort = inplace_sort = sort_inplace = sort_mutate
|
|
3054
|
+
def sort_reverse_mutate(x) -> str | list | tuple:
|
|
3055
|
+
if type(x) not in (str, list, tuple):
|
|
3056
|
+
return x
|
|
3057
|
+
was_a_string: bool = False
|
|
3058
|
+
was_a_tuple: bool = False
|
|
3059
|
+
if isinstance(x, str):
|
|
3060
|
+
x = list(x)
|
|
3061
|
+
was_a_string = True
|
|
3062
|
+
elif isinstance(x, tuple):
|
|
3063
|
+
x = list(x)
|
|
3064
|
+
was_a_tuple = True
|
|
3065
|
+
x.sort(reverse=True)
|
|
3066
|
+
# ^ return None after reverse-sorting
|
|
3067
|
+
# let's forcibly return the final x
|
|
3068
|
+
if was_a_string:
|
|
3069
|
+
x = "".join(str(item) for item in x)
|
|
3070
|
+
elif was_a_tuple:
|
|
3071
|
+
x = tuple(x)
|
|
3072
|
+
return x
|
|
3073
|
+
mutate_sort_reverse = mutate_reverse_sort = sort_mutate_reverse = reverse_mutate_sort = reverse_sort_mutate = inplace_sort_reverse = inplace_reverse_sort = sort_inplace_reverse = reverse_inplace_sort = reverse_sort_inplace = sort_reverse_mutate
|
|
3074
|
+
def reverse(x: Iterable) -> str | list | tuple | dict:
|
|
3075
|
+
if type(x) not in (str, list, tuple, dict):
|
|
3076
|
+
return x
|
|
3077
|
+
if isinstance(x, dict):
|
|
3078
|
+
reversed_kvs: dict = {v: k for k, v in x.items() if type(v) in (str, int, float)}
|
|
3079
|
+
return reversed_kvs
|
|
3080
|
+
return x[::-1]
|
|
3081
|
+
def shuffle(x: Iterable) -> str | list | tuple:
|
|
3082
|
+
if type(x) not in (str, list, tuple):
|
|
3083
|
+
return x
|
|
3084
|
+
was_a_string: bool = False
|
|
3085
|
+
was_a_tuple: bool = False
|
|
3086
|
+
if isinstance(x, str):
|
|
3087
|
+
x = list(x)
|
|
3088
|
+
was_a_string = True
|
|
3089
|
+
elif isinstance(x, tuple):
|
|
3090
|
+
x = list(x)
|
|
3091
|
+
was_a_tuple = True
|
|
3092
|
+
final_x: list = x.copy() # to not mutate the original x
|
|
3093
|
+
random.shuffle(final_x)
|
|
3094
|
+
# ^ return None after shuffling
|
|
3095
|
+
# let's forcibly return the final x
|
|
3096
|
+
if was_a_string:
|
|
3097
|
+
final_x = "".join(str(item) for item in final_x)
|
|
3098
|
+
elif was_a_tuple:
|
|
3099
|
+
final_x = tuple(final_x)
|
|
3100
|
+
return final_x
|
|
3101
|
+
shuffled = shuffle
|
|
3102
|
+
def shuffle_mutate(x: Iterable) -> str | list | tuple:
|
|
3103
|
+
if type(x) not in (str, list, tuple):
|
|
3104
|
+
return x
|
|
3105
|
+
was_a_string: bool = False
|
|
3106
|
+
was_a_tuple: bool = False
|
|
3107
|
+
if isinstance(x, str):
|
|
3108
|
+
x = list(x)
|
|
3109
|
+
was_a_string = True
|
|
3110
|
+
elif isinstance(x, tuple):
|
|
3111
|
+
x = list(x)
|
|
3112
|
+
was_a_tuple = True
|
|
3113
|
+
random.shuffle(x)
|
|
3114
|
+
# ^ return None after shuffling
|
|
3115
|
+
# let's forcibly return the final x
|
|
3116
|
+
final_x: list = x
|
|
3117
|
+
if was_a_string:
|
|
3118
|
+
final_x = "".join(str(item) for item in final_x)
|
|
3119
|
+
elif was_a_tuple:
|
|
3120
|
+
final_x = tuple(final_x)
|
|
3121
|
+
return final_x
|
|
3122
|
+
mutate_shuffle = inplace_shuffle = shuffle_inplace = shuffle_mutate
|
|
3123
|
+
_filter = lambda arr, condition: filter(condition, arr)
|
|
3124
|
+
# test this
|
|
3125
|
+
def rng_old(x: str|list|tuple|Number, y: str|list|tuple|Number|None = None, step: Number = 1, inclusive: bool = True, **kwargs) -> list[int] | list[float] | list[str]:
|
|
3126
|
+
if x is None or not isinstance(x, (str, list, tuple, Number)) or not isinstance(y, (str, list, tuple, Number, NoneType)) or step is None or not isinstance(step, Number):
|
|
3127
|
+
return []
|
|
3128
|
+
x_is_a_parsable_char: bool = False
|
|
3129
|
+
y_is_a_parsable_char: bool = False
|
|
3130
|
+
if isinstance(x, str) and len(str(x).strip()) == 1 and 0 <= ord(x) <= 127:
|
|
3131
|
+
if not y:
|
|
3132
|
+
y = ord(x[0])
|
|
3133
|
+
x = 97 if x[0].lower() == x[0] else 65
|
|
3134
|
+
else:
|
|
3135
|
+
x = ord(x[0])
|
|
3136
|
+
x_is_a_parsable_char = True
|
|
3137
|
+
if isinstance(y, str) and len(str(y).strip()) != 0 and 0 <= ord(y) <= 127:
|
|
3138
|
+
y = ord(y[0])
|
|
3139
|
+
y_is_a_parsable_char = True
|
|
3140
|
+
char_mode: bool = x_is_a_parsable_char and y_is_a_parsable_char
|
|
3141
|
+
if len(kwargs):
|
|
3142
|
+
if "s" in kwargs:
|
|
3143
|
+
step = kwargs.get("s", 1)
|
|
3144
|
+
elif "step" in kwargs:
|
|
3145
|
+
step = kwargs.get("step", 1)
|
|
3146
|
+
if "incl" in kwargs:
|
|
3147
|
+
inclusive = kwargs.get("incl", inclusive)
|
|
3148
|
+
elif "shamil" in kwargs:
|
|
3149
|
+
inclusive = kwargs.get("shamil", inclusive)
|
|
3150
|
+
elif "shamil_akhri" in kwargs:
|
|
3151
|
+
inclusive = kwargs.get("shamil_akhri", inclusive)
|
|
3152
|
+
elif "shaamil" in kwargs:
|
|
3153
|
+
inclusive = kwargs.get("shaamil", inclusive)
|
|
3154
|
+
elif "shaamil_akhri" in kwargs:
|
|
3155
|
+
inclusive = kwargs.get("shaamil_akhri", inclusive)
|
|
3156
|
+
if step <= 0:
|
|
3157
|
+
step = 1
|
|
3158
|
+
if (isinstance(y, Number) and step >= y):
|
|
3159
|
+
step = 1
|
|
3160
|
+
if isinstance(x, (str, list, tuple)) and step >= len(x):
|
|
3161
|
+
step = 1
|
|
3162
|
+
if isinstance(y, (str, list, tuple)) and step >= len(y):
|
|
3163
|
+
step = 1
|
|
3164
|
+
if isinstance(step, Number) and step % 1 == 0:
|
|
3165
|
+
step = int(step)
|
|
3166
|
+
exclusive = not inclusive
|
|
3167
|
+
return_list: list[int] | list[float] = []
|
|
3168
|
+
if y is None:
|
|
3169
|
+
inclusive = False
|
|
3170
|
+
if not isinstance(x, Number) and isinstance(step, (int, float)):
|
|
3171
|
+
if char_mode:
|
|
3172
|
+
step = int(step)
|
|
3173
|
+
i: int = 0
|
|
3174
|
+
while i < len(x):
|
|
3175
|
+
return_list.append(i)
|
|
3176
|
+
i += step
|
|
3177
|
+
if exclusive and len(return_list):
|
|
3178
|
+
return_list = return_list[:-1]
|
|
3179
|
+
return return_list
|
|
3180
|
+
x = abs(x)
|
|
3181
|
+
if isinstance(x, int) and isinstance(step, (int, float)):
|
|
3182
|
+
i: int = 0
|
|
3183
|
+
while i < x:
|
|
3184
|
+
return_list.append(i)
|
|
3185
|
+
i += step
|
|
3186
|
+
if isinstance(x, float):
|
|
3187
|
+
i: float = 0
|
|
3188
|
+
while i < x:
|
|
3189
|
+
return_list.append(i)
|
|
3190
|
+
i += step
|
|
3191
|
+
if inclusive and len(return_list):
|
|
3192
|
+
return_list.append(x)
|
|
3193
|
+
return return_list
|
|
3194
|
+
if (isinstance(x, int) and isinstance(step, (int, float))) and not isinstance(y, Number):
|
|
3195
|
+
if char_mode:
|
|
3196
|
+
step = int(step)
|
|
3197
|
+
y_length: int = len(y)
|
|
3198
|
+
if x < 0 or x >= y_length:
|
|
3199
|
+
return []
|
|
3200
|
+
while x < y_length:
|
|
3201
|
+
return_list.append(x)
|
|
3202
|
+
x += step
|
|
3203
|
+
if exclusive and len(return_list):
|
|
3204
|
+
return_list = return_list[:-1]
|
|
3205
|
+
return return_list
|
|
3206
|
+
elif isinstance(x, int) and isinstance(y, int) and isinstance(step, (int, float)):
|
|
3207
|
+
if char_mode:
|
|
3208
|
+
step = int(step)
|
|
3209
|
+
if x == y:
|
|
3210
|
+
return []
|
|
3211
|
+
if x > y:
|
|
3212
|
+
while x >= y:
|
|
3213
|
+
return_list.append(x)
|
|
3214
|
+
x -= step
|
|
3215
|
+
else:
|
|
3216
|
+
while x <= y:
|
|
3217
|
+
return_list.append(x)
|
|
3218
|
+
x += step
|
|
3219
|
+
elif isinstance(x, float) or isinstance(y, float):
|
|
3220
|
+
if x == y:
|
|
3221
|
+
return []
|
|
3222
|
+
if x > y:
|
|
3223
|
+
while x >= y:
|
|
3224
|
+
return_list.append(x)
|
|
3225
|
+
x -= step
|
|
3226
|
+
else:
|
|
3227
|
+
while x <= y:
|
|
3228
|
+
return_list.append(x)
|
|
3229
|
+
x += step
|
|
3230
|
+
if x_is_a_parsable_char or y_is_a_parsable_char:
|
|
3231
|
+
return_list = [chr(n) for n in return_list]
|
|
3232
|
+
if exclusive and len(return_list):
|
|
3233
|
+
return_list = return_list[:-1]
|
|
3234
|
+
return return_list
|
|
3235
|
+
def rng(
|
|
3236
|
+
x: Union[str, Iterable, Number],
|
|
3237
|
+
y: Union[str, Iterable, Number, None] = None,
|
|
3238
|
+
step: Number = 1,
|
|
3239
|
+
inclusive: int | bool = True,
|
|
3240
|
+
reverse: bool = False,
|
|
3241
|
+
**kwargs
|
|
3242
|
+
) -> list[str | int | float]:
|
|
3243
|
+
step: int | float = kwargs.get("s", kwargs.get("step", step))
|
|
3244
|
+
incl_flags: list[str] = ["incl", "shamil", "shamil_akhri", "shaamil", "shaamil_akhri"]
|
|
3245
|
+
rev_flags: list[str] = ["reversed", "rev", "ulat", "ulta", "ulti", "ulte"]
|
|
3246
|
+
force_inclusive = isinstance(inclusive, int) and inclusive == 2
|
|
3247
|
+
for flag in incl_flags:
|
|
3248
|
+
if flag in kwargs:
|
|
3249
|
+
val = kwargs[flag]
|
|
3250
|
+
inclusive = isinstance(val, (int, bool)) and val in (1, 2, True)
|
|
3251
|
+
if val == 2:
|
|
3252
|
+
force_inclusive = True
|
|
3253
|
+
break
|
|
3254
|
+
for flag in rev_flags:
|
|
3255
|
+
if flag in kwargs:
|
|
3256
|
+
reverse = bool(kwargs[flag])
|
|
3257
|
+
break
|
|
3258
|
+
if not isinstance(step, Number) or isinstance(step, bool):
|
|
3259
|
+
step = 1
|
|
3260
|
+
try:
|
|
3261
|
+
step_val = float(step)
|
|
3262
|
+
except (ValueError, TypeError):
|
|
3263
|
+
step_val = 1.0
|
|
3264
|
+
if step_val <= 0:
|
|
3265
|
+
step_val = 1.0
|
|
3266
|
+
char_mode = False
|
|
3267
|
+
def get_char_ord(s: str) -> int:
|
|
3268
|
+
if not s:
|
|
3269
|
+
return 0
|
|
3270
|
+
stripped = s.strip()
|
|
3271
|
+
target = stripped[0] if stripped else s[0]
|
|
3272
|
+
return ord(target)
|
|
3273
|
+
if y is None:
|
|
3274
|
+
start_val = 0.0
|
|
3275
|
+
if isinstance(x, str) and len(x) > 0:
|
|
3276
|
+
char_mode = True
|
|
3277
|
+
start_val = 97.0 if x[0].islower() else 65.0
|
|
3278
|
+
end_val = float(get_char_ord(x))
|
|
3279
|
+
elif isinstance(x, Iterable) and not isinstance(x, str):
|
|
3280
|
+
end_val = float(len(x))
|
|
3281
|
+
elif isinstance(x, Number) and not isinstance(x, bool):
|
|
3282
|
+
try:
|
|
3283
|
+
end_val = float(x)
|
|
3284
|
+
except (ValueError, TypeError):
|
|
3285
|
+
return []
|
|
3286
|
+
else:
|
|
3287
|
+
return []
|
|
3288
|
+
if not char_mode and not force_inclusive:
|
|
3289
|
+
inclusive = False
|
|
3290
|
+
else:
|
|
3291
|
+
if isinstance(x, str) and len(x) > 0:
|
|
3292
|
+
char_mode = True
|
|
3293
|
+
start_val = float(get_char_ord(x))
|
|
3294
|
+
elif isinstance(x, Number) and not isinstance(x, bool):
|
|
3295
|
+
start_val = float(x)
|
|
3296
|
+
else:
|
|
3297
|
+
start_val = 0.0
|
|
3298
|
+
if isinstance(y, str) and len(y) > 0:
|
|
3299
|
+
char_mode = True
|
|
3300
|
+
end_val = float(get_char_ord(y))
|
|
3301
|
+
elif isinstance(y, Iterable) and not isinstance(y, str):
|
|
3302
|
+
end_val = float(len(y))
|
|
3303
|
+
if not force_inclusive: inclusive = False
|
|
3304
|
+
if start_val < 0 or start_val >= end_val:
|
|
3305
|
+
return []
|
|
3306
|
+
elif isinstance(y, Number) and not isinstance(y, bool):
|
|
3307
|
+
end_val = float(y)
|
|
3308
|
+
else:
|
|
3309
|
+
return []
|
|
3310
|
+
if force_inclusive:
|
|
3311
|
+
inclusive = True
|
|
3312
|
+
if not (math.isfinite(start_val) and math.isfinite(end_val) and math.isfinite(step_val)):
|
|
3313
|
+
return []
|
|
3314
|
+
result_floats = []
|
|
3315
|
+
if start_val <= end_val:
|
|
3316
|
+
current = start_val
|
|
3317
|
+
while current < end_val or (inclusive and math.isclose(current, end_val, rel_tol=1e-12, abs_tol=1e-12)):
|
|
3318
|
+
result_floats.append(current)
|
|
3319
|
+
current += step_val
|
|
3320
|
+
if current == start_val:
|
|
3321
|
+
break
|
|
3322
|
+
else:
|
|
3323
|
+
current = start_val
|
|
3324
|
+
while current > end_val or (inclusive and math.isclose(current, end_val, rel_tol=1e-12, abs_tol=1e-12)):
|
|
3325
|
+
result_floats.append(current)
|
|
3326
|
+
current -= step_val
|
|
3327
|
+
if current == start_val:
|
|
3328
|
+
break
|
|
3329
|
+
if not result_floats:
|
|
3330
|
+
return []
|
|
3331
|
+
if reverse:
|
|
3332
|
+
result_floats = result_floats[::-1]
|
|
3333
|
+
if char_mode:
|
|
3334
|
+
return [chr(int(round(n))) for n in result_floats if 0 <= int(round(n)) <= 0x10FFFF]
|
|
3335
|
+
result_floats = [round(n, 1) for n in result_floats]
|
|
3336
|
+
if all(n.is_integer() for n in result_floats):
|
|
3337
|
+
return [int(round(n)) for n in result_floats]
|
|
3338
|
+
return result_floats
|
|
3339
|
+
def f(*args) -> str:
|
|
3340
|
+
formatted: str = ""
|
|
3341
|
+
curframe: Optional[FrameType] = currentframe()
|
|
3342
|
+
frames: list[Optional[FrameType]] = []
|
|
3343
|
+
caller_locals: dict[str, Any] = {}
|
|
3344
|
+
while curframe is not None:
|
|
3345
|
+
frames.append(curframe)
|
|
3346
|
+
curframe = curframe.f_back
|
|
3347
|
+
# keep retrieving until you hit the oldest ancestor
|
|
3348
|
+
frames = reversed(frames)
|
|
3349
|
+
# reverse the frames to prioritize the closest local scope first
|
|
3350
|
+
for scope in frames:
|
|
3351
|
+
caller_locals.update(scope.f_globals | scope.f_locals)
|
|
3352
|
+
blacklisted_keywords: list[str] = ['import', '__', 'open', 'exec', 'eval', 'del', 'lambda']
|
|
3353
|
+
blacklisted_functions: list[str] = ['system', 'popen', 'subprocess']
|
|
3354
|
+
blacklisted_items: list[str] = [*blacklisted_keywords, *blacklisted_functions]
|
|
3355
|
+
for arg in args:
|
|
3356
|
+
if isinstance(arg, bool):
|
|
3357
|
+
arg = "Yes" if arg == True else "No"
|
|
3358
|
+
try:
|
|
3359
|
+
ast.parse(f"f'{arg}'")
|
|
3360
|
+
arg_lower: str = arg.lower()
|
|
3361
|
+
for item in blacklisted_items:
|
|
3362
|
+
if item in arg_lower:
|
|
3363
|
+
print(f"Forbidden keyword/function in input: '{item}'")
|
|
3364
|
+
continue
|
|
3365
|
+
# Evaluate the expression
|
|
3366
|
+
arg = re.sub(r"(?<!\\)[\$\{]+([^\s\{\}\(\)\$]+(?:\(([\w\.\-]+(,\s*)?)*\))?)(\}(?!#{4}))?", r"{\1}", arg)
|
|
3367
|
+
# (?<!\\) means recognize escapes, and only match if the dollar '$', and opening_brace '{'' are not precededed by a forward slash '\' (which is the standard pattern for regex escapes)
|
|
3368
|
+
evaluation: str = eval(f"f'{arg}'", {"__builtins__": {}}, caller_locals)
|
|
3369
|
+
WHITESPACE_CHAR = " "
|
|
3370
|
+
# for readability, there should be a whitespace character after each argument, except the last one (though, for the last one, it does not really matter, as it usually goes unnoticed)
|
|
3371
|
+
formatted += evaluation + WHITESPACE_CHAR
|
|
3372
|
+
except Exception as e:
|
|
3373
|
+
...
|
|
3374
|
+
formatted = formatted.rstrip()
|
|
3375
|
+
return formatted
|
|
3376
|
+
def printf(*args, **kwargs) -> None:
|
|
3377
|
+
print(f(*args), **kwargs)
|
|
3378
|
+
kaho = printf
|
|
3379
|
+
def khali(x: Iterable) -> bool:
|
|
3380
|
+
if x is None:
|
|
3381
|
+
return True
|
|
3382
|
+
if not isinstance(x, Iterable):
|
|
3383
|
+
return not x
|
|
3384
|
+
if isinstance(x, str):
|
|
3385
|
+
return not x.strip()
|
|
3386
|
+
return len(x) == 0
|
|
3387
|
+
is_empty = isempty = khali_he = khali
|
|
3388
|
+
# type checks
|
|
3389
|
+
is_none = isnone = is_null = isnull = lambda x: x is None
|
|
3390
|
+
isnt_none = isntnone = non_none = nonnone = lambda x: not is_none(x)
|
|
3391
|
+
isstr = is_str = isstring = is_string = hestr = he_str = hestring = he_string = lambda x: isinstance(x, str)
|
|
3392
|
+
isnt_string = isntstring = isnt_str = isntstr = non_string = nonstring = non_str = nonstr = lambda x: not is_string(x)
|
|
3393
|
+
isint = is_int = isinteger = is_integer = heint = he_int = heinteger = he_integer = lambda x: isinstance(x, int) and not isinstance(x, bool)
|
|
3394
|
+
isnt_integer = isntinteger = isnt_int = isntint = non_integer = noninteger = non_int = nonint = lambda x: not is_integer(x)
|
|
3395
|
+
|
|
3396
|
+
def is_int_like(x: str) -> bool:
|
|
3397
|
+
if isinstance(x, bool):
|
|
3398
|
+
return True
|
|
3399
|
+
x = str(x)
|
|
3400
|
+
parsed: int = 0
|
|
3401
|
+
try:
|
|
3402
|
+
parsed = int(x)
|
|
3403
|
+
return True
|
|
3404
|
+
except ValueError:
|
|
3405
|
+
...
|
|
3406
|
+
return False
|
|
3407
|
+
he_int_jesa = he_int_jesi = he_parsable_int = is_parsable_int = is_int_like
|
|
3408
|
+
isflt = is_flt = isfloat = is_float = isdbl = is_dbl = isdouble = is_double = heflt = he_flt = hefloat = he_float = lambda x: isinstance(x, float) and not isinstance(x, bool)
|
|
3409
|
+
isnt_float = isntfloat = isnt_float = isntfloat = non_float = nonfloat = non_flt = nonflt = lambda x: not is_float(x)
|
|
3410
|
+
def is_float_like(x: str) -> bool:
|
|
3411
|
+
x = str(x)
|
|
3412
|
+
parsed: float = 0.0
|
|
3413
|
+
try:
|
|
3414
|
+
parsed = float(x)
|
|
3415
|
+
return True
|
|
3416
|
+
except ValueError:
|
|
3417
|
+
...
|
|
3418
|
+
return False
|
|
3419
|
+
he_flt_jesa = he_flt_jesi = he_parsable_flt = is_parsable_flt = is_flt_like = he_float_jesa = he_float_jesi = he_parsable_float = is_parsable_float = is_float_like = is_float_like
|
|
3420
|
+
isnr = is_nr = isnum = is_num = isnumber = is_number = henr = he_nr = henum = he_num = henumber = he_number = lambda x: isinstance(x, (int, float))
|
|
3421
|
+
is_boolean = isboolean = is_bool = isbool = hebool = he_bool = heboolean = he_boolean = hehaal = he_haal = lambda x: isinstance(x, bool)
|
|
3422
|
+
isnt_boolean = isntboolean = isnt_bool = isntbool = non_boolean = nonboolean = non_bool = nonbool = lambda x: not is_boolean(x)
|
|
3423
|
+
def is_bool_like(x: str) -> bool:
|
|
3424
|
+
x = str(x)
|
|
3425
|
+
parsed: bool = False
|
|
3426
|
+
if x == "True":
|
|
3427
|
+
parsed = True
|
|
3428
|
+
elif x == "False":
|
|
3429
|
+
parsed = False
|
|
3430
|
+
return parsed
|
|
3431
|
+
islist = is_list = helist = he_list = lambda x: isinstance(x, list)
|
|
3432
|
+
isnt_list = isntlist = lambda x: not is_list(x)
|
|
3433
|
+
is_stringlist = is_stringarr = is_strlist = is_strarr = isstringlist = isstringarr = isstrlist = isstrarr = lambda x: isinstance(x, (list[str], tuple[str, ...]))
|
|
3434
|
+
isnt_stringlist = isnt_stringarr = isnt_strlist = isnt_strarr = isntstringlist = isntstringarr = isntstrlist = isntstrarr = non_stringlist = non_stringarr = non_strlist = non_strarr = nonstringlist = nonstringarr = nonstrlist = nonstrarr = lambda x: not is_stringlist(x)
|
|
3435
|
+
is_integerlist = is_integerarr = is_intlist = is_intarr = isintegerlist = isintegerarr = isintlist = isintarr = lambda x: isinstance(x, (list[int], tuple[int, ...]))
|
|
3436
|
+
isnt_integerlist = isnt_integerarr = isnt_intlist = isnt_intarr = isntintegerlist = isntintegerarr = isntintlist = isntintarr = non_integerlist = non_integerarr = non_intlist = non_intarr = nonintegerlist = nonintegerarr = nonintlist = nonintarr = lambda x: not is_integerlist(x)
|
|
3437
|
+
is_floatlist = is_floatarr = is_fltlist = is_fltarr = isfloatlist = isfloatarr = isfltlist = isfltarr = lambda x: isinstance(x, (list[float], tuple[float, ...]))
|
|
3438
|
+
isnt_floatlist = isnt_floatarr = isnt_fltlist = isnt_fltarr = isntfloatlist = isntfloatarr = isntfltlist = isntfltarr = non_floatlist = non_floatarr = non_fltlist = non_fltarr = nonfloatlist = nonfloatarr = nonfltlist = nonfltarr = lambda x: not is_floatlist(x)
|
|
3439
|
+
is_booleanlist = is_booleanarr = is_boollist = is_boolarr = isbooleanlist = isbooleanarr = isboollist = isboolarr = lambda x: isinstance(x, (list[bool], tuple[bool, ...]))
|
|
3440
|
+
isnt_booleanlist = isnt_booleanarr = isnt_boollist = isnt_boolarr = isntbooleanlist = isntbooleanarr = isntboollist = isntboolarr = non_booleanlist = non_booleanarr = non_boollist = non_boolarr = nonbooleanlist = nonbooleanarr = nonboollist = nonboolarr = lambda x: not is_booleanlist(x)
|
|
3441
|
+
is_iterable = isiterable = lambda x: isinstance(x, Iterable)
|
|
3442
|
+
isnt_iterable = isntiterable = non_iterable = noniterable = lambda x: not is_iterable(x)
|
|
3443
|
+
istuple = is_tuple = hetuple = he_tuple = lambda x: isinstance(x, tuple)
|
|
3444
|
+
isset = is_set = heset = he_set = lambda x: isinstance(x, set)
|
|
3445
|
+
isdict = is_dict = isdictionary = is_dictionary = hedict = he_dict = hedictionary = he_dictionary = lambda x: isinstance(x, dict)
|
|
3446
|
+
is_callable = iscallable = is_function = isfunction = is_func = isfunc = lambda x: callable(x)
|
|
3447
|
+
isnt_callable = isntcallable = non_callable = noncallable = lambda x: not is_callable(x)
|
|
3448
|
+
def split(src: str, regex: str|NoneType = None, maxsplits: int = IntInfinity, flags: int = 0) -> list[str]:
|
|
3449
|
+
if not src or not isinstance(src, str) or not isinstance(regex, (str, NoneType)):
|
|
3450
|
+
# allow regex to be empty, as it sometimes can be
|
|
3451
|
+
return []
|
|
3452
|
+
if regex is None:
|
|
3453
|
+
# if the regex is None, split into words (hyphen, and quote preserved, for max reliability)
|
|
3454
|
+
regex = r"([^\-\w\"\']|(?<!\w)[\-\"\'](?!\w))"
|
|
3455
|
+
regex = str(regex)
|
|
3456
|
+
if not isinstance(maxsplits, int):
|
|
3457
|
+
maxsplits = IntInfinity
|
|
3458
|
+
if maxsplits <= 0:
|
|
3459
|
+
return [src]
|
|
3460
|
+
if not isinstance(flags, int):
|
|
3461
|
+
flags = 0
|
|
3462
|
+
try:
|
|
3463
|
+
regex = re.sub(r"(\?)(<\w+>)", r"\1P\2", regex)
|
|
3464
|
+
raw_list: list[str] = re.split(regex, src, maxsplit=maxsplits, flags=flags)
|
|
3465
|
+
result: list[str] = []
|
|
3466
|
+
for x in raw_list:
|
|
3467
|
+
if not x:
|
|
3468
|
+
continue
|
|
3469
|
+
result.append(x)
|
|
3470
|
+
return result
|
|
3471
|
+
except re.error as e:
|
|
3472
|
+
# fallback to original splitting
|
|
3473
|
+
# if regex splitting fails
|
|
3474
|
+
print(f"re.warning:\n * Bad regex split pattern. Falling back to the original `'string'.split`. *Reason*: {str(e).capitalize()}.")
|
|
3475
|
+
return [x for x in src.split(regex) if x]
|
|
3476
|
+
def joined_words(*args: tuple[Any]) -> str:
|
|
3477
|
+
"""
|
|
3478
|
+
@param args
|
|
3479
|
+
:type tuple[Any]
|
|
3480
|
+
:description arguments to join in "x, y, aur z" format
|
|
3481
|
+
@return
|
|
3482
|
+
:type str <blankable, if len(args) == 0>
|
|
3483
|
+
:description the joined arguments (initially of type, Any)
|
|
3484
|
+
"""
|
|
3485
|
+
result: list[str] = []
|
|
3486
|
+
for arg in args:
|
|
3487
|
+
if arg is None:
|
|
3488
|
+
continue
|
|
3489
|
+
if isinstance(arg, (list, tuple)):
|
|
3490
|
+
arg = joined_words(*arg)
|
|
3491
|
+
arg = re.sub(r"(?<=, )aur (?=.+$)", "", str(arg))
|
|
3492
|
+
if isinstance(arg, float):
|
|
3493
|
+
arg = round(arg, 1)
|
|
3494
|
+
if isinstance(arg, bool):
|
|
3495
|
+
arg = "Han" if arg else "Nahi"
|
|
3496
|
+
arg = str(arg)
|
|
3497
|
+
if ", " in arg:
|
|
3498
|
+
sub_args: list[str] = arg.split(", ")
|
|
3499
|
+
for sub_arg in sub_args:
|
|
3500
|
+
result.append(sub_arg)
|
|
3501
|
+
continue
|
|
3502
|
+
result.append(arg)
|
|
3503
|
+
if len(result) < 2:
|
|
3504
|
+
return ", ".join(result)
|
|
3505
|
+
last: str = str(result.pop())
|
|
3506
|
+
return ", ".join(result) + ", aur " + last
|
|
3507
|
+
jurewe = joined_words
|
|
3508
|
+
def split_into_words(s: str) -> list[str]:
|
|
3509
|
+
if not isinstance(s, str) or not s.strip(): return ""
|
|
3510
|
+
return re.findall(WORD_RE, s)
|
|
3511
|
+
find_words = findwords = to_words = towords = to_word_list = towordlist = pakro_words = pakrowords = pakro_alfaaz = pakroalfaaz = split_into_words
|
|
3512
|
+
def json_load(filename: str) -> dict | list:
|
|
3513
|
+
if not isinstance(filename, str) or not filename.strip():
|
|
3514
|
+
return {}
|
|
3515
|
+
filename = os.path.normpath(filename)
|
|
3516
|
+
if "." not in filename:
|
|
3517
|
+
filename += ".json"
|
|
3518
|
+
if not os.path.exists(filename):
|
|
3519
|
+
return {}
|
|
3520
|
+
contents: Any = {}
|
|
3521
|
+
try:
|
|
3522
|
+
with open(filename, mode="r") as file:
|
|
3523
|
+
contents = json.load(file)
|
|
3524
|
+
except Exception as e:
|
|
3525
|
+
print(e)
|
|
3526
|
+
# the loaded contents can be a list, too
|
|
3527
|
+
# not always a dictionary
|
|
3528
|
+
if isinstance(contents, dict) and "Obj" in globals():
|
|
3529
|
+
contents = Obj(contents)
|
|
3530
|
+
return contents
|
|
3531
|
+
load_json = loadjson = jsonload = json_load
|
|
3532
|
+
def replace(src: str, to_replace: str|dict|None = None, replacement: str|Callable = "", ignore_case: bool = False, case_insensitive: bool = False, count: int = IntInfinity) -> str:
|
|
3533
|
+
if not src or not isinstance(src, str) or not ((isinstance(to_replace, str)) or (isinstance(to_replace, dict) and not replacement) or isinstance(replacement, (str, Callable))):
|
|
3534
|
+
# allow empty replacement for removals
|
|
3535
|
+
return ""
|
|
3536
|
+
ignore_case = ignore_case or case_insensitive
|
|
3537
|
+
if not ignore_case or not isinstance(ignore_case, bool):
|
|
3538
|
+
ignore_case = False
|
|
3539
|
+
if not isinstance(count, int) or count < 0:
|
|
3540
|
+
count = IntInfinity
|
|
3541
|
+
if isinstance(to_replace, str):
|
|
3542
|
+
if not len(to_replace):
|
|
3543
|
+
return src
|
|
3544
|
+
if not re.search(r"[\(\)]", to_replace):
|
|
3545
|
+
to_replace = f"({to_replace})"
|
|
3546
|
+
to_replace = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_replace)
|
|
3547
|
+
if isinstance(replacement, str):
|
|
3548
|
+
# if it's a string, rather than a callable---usually in the form of a lambda function
|
|
3549
|
+
if re.search(r"[\$\\][&0]", replacement):
|
|
3550
|
+
return src
|
|
3551
|
+
replacement = re.sub(r"\$\{?(\d+)(\}(?!#{4}))?", r"\\\1", replacement) # the function sees and uses 4 hashes (####) as an escape sequence for a replacement regex group's closing brace
|
|
3552
|
+
# achieve JavaScript-like numbered-group convention ^
|
|
3553
|
+
replacement = re.sub(r"\$\{?([A-Za-z]\w*)(\}(?!#{4}))?", r"\\g<\1>", replacement) # the function sees and uses 4 hashes (####) as an escape sequence for a replacement regex group's closing brace
|
|
3554
|
+
# achieve JavaScript-like named-group convention ^
|
|
3555
|
+
flags: int = re.MULTILINE
|
|
3556
|
+
if ignore_case:
|
|
3557
|
+
flags |= re.IGNORECASE
|
|
3558
|
+
result: str = ""
|
|
3559
|
+
if not replacement and isinstance(to_replace, dict):
|
|
3560
|
+
result = src
|
|
3561
|
+
# for now
|
|
3562
|
+
for key, value in to_replace.items():
|
|
3563
|
+
if not key.strip():
|
|
3564
|
+
continue
|
|
3565
|
+
result = replace(result, key, value)
|
|
3566
|
+
return result
|
|
3567
|
+
if not isinstance(to_replace, str):
|
|
3568
|
+
to_replace = ""
|
|
3569
|
+
try:
|
|
3570
|
+
result = re.sub(to_replace, replacement, src, flags=flags, count=count)
|
|
3571
|
+
except re.error as e:
|
|
3572
|
+
src_trunc: str = f"{src[:30]}... ..." if len(src) > 30 else src
|
|
3573
|
+
print(f"re.warning:\n * Bad regex, or replacement pattern '{to_replace}'. Returning the original source string '{src_trunc}' as-is. *Reason*: {str(e).capitalize()}.")
|
|
3574
|
+
result = src
|
|
3575
|
+
return result
|
|
3576
|
+
replacei = ireplace = replace_i = i_replace = functools.partial(replace, ignore_case=True)
|
|
3577
|
+
replaceone = replace_one = functools.partial(replace, count=1)
|
|
3578
|
+
replace_i_one = replace_one_i = replace_ione = replace_onei = replace_ins_first = replace_first_ins = replace_insfirst = functools.partial(replace, ignore_case=True, count=1)
|
|
3579
|
+
def find_matches(src: str, to_find: str) -> list[str]:
|
|
3580
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3581
|
+
return []
|
|
3582
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3583
|
+
matches: list[str] = re.findall(to_find, src)
|
|
3584
|
+
return matches
|
|
3585
|
+
def find_matches_i(src: str, to_find: str) -> list[str]:
|
|
3586
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3587
|
+
return []
|
|
3588
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3589
|
+
matches: list[str] = re.findall(to_find, src, re.IGNORECASE)
|
|
3590
|
+
return matches
|
|
3591
|
+
def find_matches_as_obj(src: str, to_find: str) -> obj[str, str]:
|
|
3592
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3593
|
+
return obj()
|
|
3594
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3595
|
+
matches: obj[str, str] = obj()
|
|
3596
|
+
if matches_found := re.search(to_find, src):
|
|
3597
|
+
matches = matches_found.groupdict()
|
|
3598
|
+
return matches
|
|
3599
|
+
def find_matches_as_obj_i(src: str, to_find: str) -> obj[str, str]:
|
|
3600
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3601
|
+
return obj()
|
|
3602
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3603
|
+
matches: obj[str, str] = obj()
|
|
3604
|
+
if matches_found := re.search(to_find, src, flags=re.IGNORECASE):
|
|
3605
|
+
matches = matches_found.groupdict()
|
|
3606
|
+
return matches
|
|
3607
|
+
def find_match(src: str, to_find: str) -> str:
|
|
3608
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3609
|
+
return ""
|
|
3610
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3611
|
+
matches: list[str] = find_matches(src, to_find)
|
|
3612
|
+
if len(matches) == 0:
|
|
3613
|
+
return ""
|
|
3614
|
+
return matches[0]
|
|
3615
|
+
def find_match_i(src: str, to_find: str) -> str:
|
|
3616
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3617
|
+
return ""
|
|
3618
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3619
|
+
matches: list[str] = find_matches_i(src, to_find)
|
|
3620
|
+
if len(matches) == 0 or not matches[0]:
|
|
3621
|
+
return ""
|
|
3622
|
+
return matches[0]
|
|
3623
|
+
def match(src: str, to_find: str) -> bool:
|
|
3624
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3625
|
+
return False
|
|
3626
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3627
|
+
matches: list[str] = find_matches(src, to_find)
|
|
3628
|
+
if len(matches) == 0:
|
|
3629
|
+
return False
|
|
3630
|
+
return True
|
|
3631
|
+
def match_i(src: str, to_find: str) -> bool:
|
|
3632
|
+
if not src or not isinstance(src, str) or not to_find or not isinstance(to_find, str):
|
|
3633
|
+
return False
|
|
3634
|
+
to_find = re.sub(r"(\?)(<\w+>)", r"\1P\2", to_find)
|
|
3635
|
+
matches: list[str] = find_matches_i(src, to_find)
|
|
3636
|
+
if len(matches) == 0:
|
|
3637
|
+
return False
|
|
3638
|
+
return True
|
|
3639
|
+
hasmatch = has_match = match
|
|
3640
|
+
hasmatchi = has_match_i = match_i
|
|
3641
|
+
def find_words(src: Any) -> list[str]:
|
|
3642
|
+
"""
|
|
3643
|
+
@param src
|
|
3644
|
+
:type Any
|
|
3645
|
+
:description the source to find the words from
|
|
3646
|
+
@return
|
|
3647
|
+
:type list <blankable, if no words are found>
|
|
3648
|
+
:description a word list containing all the words from the object
|
|
3649
|
+
"""
|
|
3650
|
+
if not src:
|
|
3651
|
+
return ""
|
|
3652
|
+
src = str(src).strip()
|
|
3653
|
+
word_list: list[str] = find_matches(src, r"(?:[A-Za-z]+\-)*[A-Za-z]+")
|
|
3654
|
+
return word_list
|
|
3655
|
+
dhundo_alfaaz = dhundo_alfaz = words_of = to_words = find_words
|
|
3656
|
+
def startswith(x: str|list, y: str|list) -> bool:
|
|
3657
|
+
if not isinstance(x, (str, list, tuple)):
|
|
3658
|
+
return False
|
|
3659
|
+
if isinstance_each([x, y], str):
|
|
3660
|
+
try:
|
|
3661
|
+
return re.search(f"^{y}", x)
|
|
3662
|
+
except re.error as e:
|
|
3663
|
+
print(f"re.warning:\n * Bad regex. Switching to default `str.startswith` mode, now that the regex mode failed. *Reason*: {str(e).capitalize()}.")
|
|
3664
|
+
return x.startswith(y)
|
|
3665
|
+
elif isinstance(x, (list, tuple)):
|
|
3666
|
+
if isinstance(x, tuple):
|
|
3667
|
+
x = list(x)
|
|
3668
|
+
if not isinstance(y, (list, tuple)):
|
|
3669
|
+
y = [y]
|
|
3670
|
+
if isinstance(y, tuple):
|
|
3671
|
+
y = list(y)
|
|
3672
|
+
if len(x) < len(y):
|
|
3673
|
+
return False
|
|
3674
|
+
return x[:len(y)] == y
|
|
3675
|
+
return False
|
|
3676
|
+
starts_with = startswith
|
|
3677
|
+
def endswith(x: str|list, y: str|list) -> bool:
|
|
3678
|
+
if not isinstance(x, (str, list, tuple)):
|
|
3679
|
+
return False
|
|
3680
|
+
if isinstance_each([x, y], str):
|
|
3681
|
+
try:
|
|
3682
|
+
return re.search(f"{y}$", x)
|
|
3683
|
+
except re.error as e:
|
|
3684
|
+
print(f"re.warning:\n * Bad regex. Switching to default `str.endswith` mode, now that the regex mode failed. *Reason*: {str(e).capitalize()}.")
|
|
3685
|
+
return x.endswith(y)
|
|
3686
|
+
elif isinstance(x, (list, tuple)):
|
|
3687
|
+
if isinstance(x, tuple):
|
|
3688
|
+
x = list(x)
|
|
3689
|
+
if not isinstance(y, (list, tuple)):
|
|
3690
|
+
y = [y]
|
|
3691
|
+
if isinstance(y, tuple):
|
|
3692
|
+
y = list(y)
|
|
3693
|
+
if len(x) < len(y):
|
|
3694
|
+
return False
|
|
3695
|
+
return x[-len(y):] == y
|
|
3696
|
+
return False
|
|
3697
|
+
ends_with = endswith
|
|
3698
|
+
def upper(src: str) -> str:
|
|
3699
|
+
if not isinstance(src, str):
|
|
3700
|
+
return ""
|
|
3701
|
+
result: str = src.upper()
|
|
3702
|
+
return result
|
|
3703
|
+
def isupper(src: str) -> bool:
|
|
3704
|
+
if not isinstance(src, str):
|
|
3705
|
+
return False
|
|
3706
|
+
return src.isupper()
|
|
3707
|
+
is_upper = isupper
|
|
3708
|
+
def lower(src: str) -> str:
|
|
3709
|
+
if not isinstance(src, str):
|
|
3710
|
+
return ""
|
|
3711
|
+
result: str = src.lower()
|
|
3712
|
+
return result
|
|
3713
|
+
def islower(src: str) -> bool:
|
|
3714
|
+
if not isinstance(src, str):
|
|
3715
|
+
return False
|
|
3716
|
+
return src.islower()
|
|
3717
|
+
is_lower = islower
|
|
3718
|
+
def snake_case(src: str) -> str:
|
|
3719
|
+
if not isinstance(src, str):
|
|
3720
|
+
return ""
|
|
3721
|
+
all_were_upper: bool = False
|
|
3722
|
+
if src.upper() == src:
|
|
3723
|
+
all_were_upper = True
|
|
3724
|
+
result: str = src.casefold()
|
|
3725
|
+
result = re.sub(r"[^\-\.\w\n]+", "_", result).strip("_")
|
|
3726
|
+
if all_were_upper:
|
|
3727
|
+
result = result.upper()
|
|
3728
|
+
return result
|
|
3729
|
+
snakecase = snake_case
|
|
3730
|
+
def is_snake_case(src: str) -> bool:
|
|
3731
|
+
if not isinstance(src, str):
|
|
3732
|
+
return False
|
|
3733
|
+
return src == snake_case(src)
|
|
3734
|
+
issnakecase = is_snakecase = is_snake_case
|
|
3735
|
+
def title_case(src: str) -> str:
|
|
3736
|
+
if not isinstance(src, str):
|
|
3737
|
+
return ""
|
|
3738
|
+
result: str = src.title()
|
|
3739
|
+
return result
|
|
3740
|
+
def is_title_case(src: str) -> bool:
|
|
3741
|
+
if not isinstance(src, str):
|
|
3742
|
+
return False
|
|
3743
|
+
return src.istitle()
|
|
3744
|
+
istitle = is_title = istitlecase = is_titlecase = is_title_case
|
|
3745
|
+
def sentence_case(src: str) -> str:
|
|
3746
|
+
if not isinstance(src, str):
|
|
3747
|
+
return ""
|
|
3748
|
+
result: str = src.capitalize()
|
|
3749
|
+
return result
|
|
3750
|
+
sentcase = sent_case = sentence_case
|
|
3751
|
+
def is_sentence_case(src: str) -> bool:
|
|
3752
|
+
if not isinstance(src, str):
|
|
3753
|
+
return False
|
|
3754
|
+
return src == sentence_case(src)
|
|
3755
|
+
issentcase = is_sentcase = is_sent_case = issentencecase = is_sentencecase = is_sentence_case
|
|
3756
|
+
class Money:
|
|
3757
|
+
def __init__(self, amount=0, currency="Rs. "):
|
|
3758
|
+
self.amount = amount if amount >= 0 else 0
|
|
3759
|
+
self.currency = currency if currency and len(currency) <= 4 else "Rs. "
|
|
3760
|
+
def set_currency(self, currency):
|
|
3761
|
+
if currency and len(currency) <= 4:
|
|
3762
|
+
self.currency = currency
|
|
3763
|
+
return self
|
|
3764
|
+
def set_amount(self, new_amount):
|
|
3765
|
+
if new_amount >= 0:
|
|
3766
|
+
self.amount = new_amount
|
|
3767
|
+
return self
|
|
3768
|
+
def add(self, *nums):
|
|
3769
|
+
self.amount += sum(nums)
|
|
3770
|
+
return self
|
|
3771
|
+
def subtract(self, *nums):
|
|
3772
|
+
self.amount -= sum(nums)
|
|
3773
|
+
return self
|
|
3774
|
+
def multiply(self, *nums):
|
|
3775
|
+
for n in nums:
|
|
3776
|
+
self.amount *= n
|
|
3777
|
+
return self
|
|
3778
|
+
def divide(self, *nums):
|
|
3779
|
+
for n in nums:
|
|
3780
|
+
if n == 0:
|
|
3781
|
+
n = 1
|
|
3782
|
+
self.amount /= n
|
|
3783
|
+
return self
|
|
3784
|
+
def __str__(self):
|
|
3785
|
+
return f"{self.currency}{self.amount:.2f}"
|
|
3786
|
+
def balance(self):
|
|
3787
|
+
return str(self)
|
|
3788
|
+
class Pesa(Money):
|
|
3789
|
+
def __init__(self, amount, currency):
|
|
3790
|
+
super().__init__(amount, currency)
|
|
3791
|
+
pesa = Pesa
|
|
3792
|
+
def open_file_case_ins(filename: str, mode: str = 'r', **kwargs):
|
|
3793
|
+
filename = str(filename)
|
|
3794
|
+
if not mode or not isinstance(mode, str):
|
|
3795
|
+
mode = "r"
|
|
3796
|
+
if not filename or not os.path.isfile(filename):
|
|
3797
|
+
raise FileNotFoundError(f"File '{filename}' doesn't exist")
|
|
3798
|
+
directory, name = os.path.split(filename)
|
|
3799
|
+
directory = directory or '.' # Default to current directory if none specified
|
|
3800
|
+
name_lower = name.lower()
|
|
3801
|
+
for actual_file_name in os.listdir(directory):
|
|
3802
|
+
if actual_file_name.lower() == name_lower:
|
|
3803
|
+
actual_path = os.path.join(directory, actual_file_name)
|
|
3804
|
+
if os.path.isfile(actual_path):
|
|
3805
|
+
return open(actual_path, mode, **kwargs)
|
|
3806
|
+
open_case_ins = open_file_case_ins
|
|
3807
|
+
class File:
|
|
3808
|
+
def __init__(self, path: Union[str, Path]):
|
|
3809
|
+
self.pathname = Path(path)
|
|
3810
|
+
def __str__(self) -> str:
|
|
3811
|
+
return str(self.pathname)
|
|
3812
|
+
def path(self) -> Path:
|
|
3813
|
+
return self.pathname
|
|
3814
|
+
def absolute_path(self) -> str:
|
|
3815
|
+
return str(self.pathname.absolute())
|
|
3816
|
+
def abs_path(self) -> str:
|
|
3817
|
+
return self.absolute_path()
|
|
3818
|
+
def is_file(self) -> bool:
|
|
3819
|
+
return self.pathname.is_file()
|
|
3820
|
+
def is_folder(self) -> bool:
|
|
3821
|
+
return self.pathname.is_dir()
|
|
3822
|
+
def exists(self) -> bool:
|
|
3823
|
+
return self.pathname.exists()
|
|
3824
|
+
def exists_file(self) -> bool:
|
|
3825
|
+
return self.is_file() and self.exists()
|
|
3826
|
+
def exists_folder(self) -> bool:
|
|
3827
|
+
return self.is_folder() and self.exists()
|
|
3828
|
+
mojud_file = mojud_he_file = he_mojud_file = found_file = exists_file
|
|
3829
|
+
exists_directory = exists_dir = found_dir = mojud_folder = mojud_he_folder = he_mojud_folder = mojud_directory = mojud_he_directory = he_mojud_directory = exists_folder
|
|
3830
|
+
mojud = mojud_he = he_mojud = found = exists_path = exists
|
|
3831
|
+
@staticmethod
|
|
3832
|
+
def create(fname: str, content: str = "") -> bool:
|
|
3833
|
+
try:
|
|
3834
|
+
if not fname or not content:
|
|
3835
|
+
raise ValueError("File name, and content are required")
|
|
3836
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", fname):
|
|
3837
|
+
for subFileName in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", fname):
|
|
3838
|
+
File.create(subFileName, content)
|
|
3839
|
+
return True
|
|
3840
|
+
with open(fname, 'w') as f:
|
|
3841
|
+
f.write(content)
|
|
3842
|
+
print(f"[KL.file.JobSuccess]:\nFile {fname} created successfully.")
|
|
3843
|
+
return True
|
|
3844
|
+
except ValueError as e:
|
|
3845
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3846
|
+
except PermissionError:
|
|
3847
|
+
print(f"[KL.file.JobFailed]: Permission denied to create file {fname}")
|
|
3848
|
+
except OSError as e:
|
|
3849
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3850
|
+
except Exception as e:
|
|
3851
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3852
|
+
return False
|
|
3853
|
+
@staticmethod
|
|
3854
|
+
def createBlankFile(fname: str) -> bool:
|
|
3855
|
+
try:
|
|
3856
|
+
if not fname:
|
|
3857
|
+
raise ValueError("File name is required")
|
|
3858
|
+
Path(fname).touch()
|
|
3859
|
+
print(f"[KL.file.JobSuccess]:\nBlank file {fname} created successfully.")
|
|
3860
|
+
return True
|
|
3861
|
+
except ValueError as e:
|
|
3862
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3863
|
+
except PermissionError:
|
|
3864
|
+
print(f"[KL.file.JobFailed]: Permission denied to create file {fname}")
|
|
3865
|
+
except OSError as e:
|
|
3866
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3867
|
+
except Exception as e:
|
|
3868
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3869
|
+
return False
|
|
3870
|
+
touch = createBlankFile
|
|
3871
|
+
@staticmethod
|
|
3872
|
+
def createFolder(folderName: str) -> bool:
|
|
3873
|
+
try:
|
|
3874
|
+
if not folderName:
|
|
3875
|
+
raise ValueError("Folder name is required")
|
|
3876
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", folderName):
|
|
3877
|
+
for folder in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", folderName):
|
|
3878
|
+
File.createFolder(folder)
|
|
3879
|
+
return True
|
|
3880
|
+
os.makedirs(folderName, exist_ok=True)
|
|
3881
|
+
return True
|
|
3882
|
+
except ValueError as e:
|
|
3883
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3884
|
+
except PermissionError:
|
|
3885
|
+
print(f"[KL.file.JobFailed]: Permission denied to create folder {folderName}")
|
|
3886
|
+
except OSError as e:
|
|
3887
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3888
|
+
except Exception as e:
|
|
3889
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3890
|
+
return False
|
|
3891
|
+
@staticmethod
|
|
3892
|
+
def read(fname: str) -> str:
|
|
3893
|
+
try:
|
|
3894
|
+
if not fname:
|
|
3895
|
+
raise ValueError("File name is required")
|
|
3896
|
+
with open_case_ins(fname, 'r') as f:
|
|
3897
|
+
contents: str = f.read()
|
|
3898
|
+
return contents
|
|
3899
|
+
except ValueError as e:
|
|
3900
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3901
|
+
except FileNotFoundError:
|
|
3902
|
+
print(f"[KL.file.JobFailed]: File {fname} does not exist")
|
|
3903
|
+
except PermissionError:
|
|
3904
|
+
print(f"[KL.file.JobFailed]: Permission denied to read file {fname}")
|
|
3905
|
+
except OSError as e:
|
|
3906
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3907
|
+
except Exception as e:
|
|
3908
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3909
|
+
return ""
|
|
3910
|
+
@staticmethod
|
|
3911
|
+
def get_lines(fname: str) -> list[str]:
|
|
3912
|
+
contents: str = File.read(fname)
|
|
3913
|
+
lines: list[str] = []
|
|
3914
|
+
if not contents.strip():
|
|
3915
|
+
return False
|
|
3916
|
+
if re.search(r"\n", contents):
|
|
3917
|
+
split_content: list[str] = split(contents, r"\n")
|
|
3918
|
+
for line in split_content:
|
|
3919
|
+
lines.append(line)
|
|
3920
|
+
else:
|
|
3921
|
+
lines.append(contents)
|
|
3922
|
+
# no lines found other than the first, append the contents as-is
|
|
3923
|
+
return lines
|
|
3924
|
+
readlines = read_lines = getlines = get_lines
|
|
3925
|
+
@staticmethod
|
|
3926
|
+
def readJson(fname: str) -> Optional[dict]:
|
|
3927
|
+
try:
|
|
3928
|
+
return json.loads(File.read(fname))
|
|
3929
|
+
except json.JSONDecodeError as e:
|
|
3930
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3931
|
+
except Exception as e:
|
|
3932
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3933
|
+
return None
|
|
3934
|
+
@staticmethod
|
|
3935
|
+
def write(fname: str, content: str) -> bool:
|
|
3936
|
+
try:
|
|
3937
|
+
if not fname or not content:
|
|
3938
|
+
raise ValueError("File name and content are required")
|
|
3939
|
+
with open(fname, 'w') as f:
|
|
3940
|
+
f.write(content)
|
|
3941
|
+
print(f"[KL.file.JobSuccess]:\nFile {fname} written successfully.")
|
|
3942
|
+
return True
|
|
3943
|
+
except ValueError as e:
|
|
3944
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3945
|
+
except PermissionError:
|
|
3946
|
+
print(f"[KL.file.JobFailed]: Permission denied to write to file {fname}")
|
|
3947
|
+
except OSError as e:
|
|
3948
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3949
|
+
except Exception as e:
|
|
3950
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3951
|
+
return False
|
|
3952
|
+
@staticmethod
|
|
3953
|
+
def append(fname: str, content: str) -> bool:
|
|
3954
|
+
try:
|
|
3955
|
+
if not fname or not content:
|
|
3956
|
+
raise ValueError("File name and content are required")
|
|
3957
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", fname):
|
|
3958
|
+
for subFileName in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", fname):
|
|
3959
|
+
File.append(subFileName, content)
|
|
3960
|
+
return True
|
|
3961
|
+
with open(fname, 'a') as f:
|
|
3962
|
+
f.write(content)
|
|
3963
|
+
print(f"[KL.file.JobSuccess]:\nAppending to file {fname} was successful.")
|
|
3964
|
+
return True
|
|
3965
|
+
except ValueError as e:
|
|
3966
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3967
|
+
except PermissionError:
|
|
3968
|
+
print(f"[KL.file.JobFailed]: Permission denied to append to file {fname}")
|
|
3969
|
+
except OSError as e:
|
|
3970
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3971
|
+
except Exception as e:
|
|
3972
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3973
|
+
return False
|
|
3974
|
+
@staticmethod
|
|
3975
|
+
def delete(fname: str) -> bool:
|
|
3976
|
+
try:
|
|
3977
|
+
if not fname:
|
|
3978
|
+
return
|
|
3979
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", fname):
|
|
3980
|
+
for subFileName in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", fname):
|
|
3981
|
+
File.delete(subFileName)
|
|
3982
|
+
return True
|
|
3983
|
+
if os.path.isdir(fname):
|
|
3984
|
+
shutil.rmtree(fname)
|
|
3985
|
+
else:
|
|
3986
|
+
os.remove(fname)
|
|
3987
|
+
print(f"[KL.file.JobSuccess]:\nFile {fname} deleted successfully.")
|
|
3988
|
+
return True
|
|
3989
|
+
except FileNotFoundError:
|
|
3990
|
+
print(f"[KL.file.JobFailed]: File {fname} does not exist")
|
|
3991
|
+
except PermissionError:
|
|
3992
|
+
print(f"[KL.file.JobFailed]: Permission denied to delete file {fname}")
|
|
3993
|
+
except OSError as e:
|
|
3994
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3995
|
+
except Exception as e:
|
|
3996
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
3997
|
+
return False
|
|
3998
|
+
remove = delete
|
|
3999
|
+
@staticmethod
|
|
4000
|
+
def rename(fname: str, destinationString: str) -> bool:
|
|
4001
|
+
try:
|
|
4002
|
+
if not fname or not destinationString:
|
|
4003
|
+
raise ValueError("File name and destination are required")
|
|
4004
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", fname) and re.search(r"[\\\\\\/]", destinationString):
|
|
4005
|
+
for subFileName in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", fname):
|
|
4006
|
+
File.rename(subFileName, destinationString)
|
|
4007
|
+
return True
|
|
4008
|
+
os.replace(fname, destinationString)
|
|
4009
|
+
print(f"[KL.file.JobSuccess]:\nFile {fname} was successfully moved/renamed to {destinationString}")
|
|
4010
|
+
return True
|
|
4011
|
+
except ValueError as e:
|
|
4012
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4013
|
+
except FileNotFoundError:
|
|
4014
|
+
print(f"[KL.file.JobFailed]: File {fname} does not exist")
|
|
4015
|
+
except PermissionError:
|
|
4016
|
+
print(f"[KL.file.JobFailed]: Permission denied to rename file {fname}")
|
|
4017
|
+
except OSError as e:
|
|
4018
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4019
|
+
except Exception as e:
|
|
4020
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4021
|
+
return False
|
|
4022
|
+
move = rename
|
|
4023
|
+
@staticmethod
|
|
4024
|
+
def copy(from_path: str, to_path: str, overwrite: bool = True) -> bool:
|
|
4025
|
+
try:
|
|
4026
|
+
if not from_path or not to_path:
|
|
4027
|
+
raise ValueError("Source and destination paths are required")
|
|
4028
|
+
if re.search(r"(?<=\\w)\\s*[\\|\\+\\&\\,\\;]\\s*(?=\\w)", from_path):
|
|
4029
|
+
for subFileName in re.split(r"\\s*[\\|\\+\\&\\,\\;]\\s*", from_path):
|
|
4030
|
+
File.copy(subFileName, to_path, overwrite)
|
|
4031
|
+
return True
|
|
4032
|
+
shutil.copy2(from_path, to_path)
|
|
4033
|
+
return True
|
|
4034
|
+
except ValueError as e:
|
|
4035
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4036
|
+
except FileNotFoundError:
|
|
4037
|
+
print(f"[KL.file.JobFailed]: File {from_path} does not exist")
|
|
4038
|
+
except PermissionError:
|
|
4039
|
+
print(f"[KL.file.JobFailed]: Permission denied to copy file {from_path}")
|
|
4040
|
+
except OSError as e:
|
|
4041
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4042
|
+
except Exception as e:
|
|
4043
|
+
print(f"[KL.file.JobFailed]: {e}")
|
|
4044
|
+
return False
|
|
4045
|
+
file: File = File
|
|
4046
|
+
def encode(data: any) -> str:
|
|
4047
|
+
try:
|
|
4048
|
+
return base64.b64encode(str(data).encode()).decode()
|
|
4049
|
+
except TypeError as e:
|
|
4050
|
+
return ""
|
|
4051
|
+
def decode(data: str) -> str:
|
|
4052
|
+
import binascii
|
|
4053
|
+
try:
|
|
4054
|
+
return base64.b64decode(data).decode()
|
|
4055
|
+
except (TypeError, binascii.Error) as e:
|
|
4056
|
+
return ""
|
|
4057
|
+
|
|
4058
|
+
import time
|
|
4059
|
+
def time_it(fn):
|
|
4060
|
+
if not callable(fn):
|
|
4061
|
+
return
|
|
4062
|
+
def wrapper(*args, **kwargs):
|
|
4063
|
+
start: float = timer.time()
|
|
4064
|
+
return_value = fn(*args, **kwargs)
|
|
4065
|
+
# if possible, get the return value
|
|
4066
|
+
end: int = timer.time()
|
|
4067
|
+
duration: int = end - start
|
|
4068
|
+
print(f"@timeit:\n\tFunction `{fn.__name__}` took {duration:.3f} second(s) to fulfil its job")
|
|
4069
|
+
return return_value
|
|
4070
|
+
return wrapper
|
|
4071
|
+
def time_lia(fn):
|
|
4072
|
+
if not callable(fn):
|
|
4073
|
+
return
|
|
4074
|
+
def wrapper(*args, **kwargs):
|
|
4075
|
+
start: float = timer.time()
|
|
4076
|
+
return_value = fn(*args, **kwargs)
|
|
4077
|
+
# if possible, get the return value
|
|
4078
|
+
end: int = timer.time()
|
|
4079
|
+
duration: int = end - start
|
|
4080
|
+
print(f"@timelia:\n\tFunction `{fn.__name__}` ne apna kaam {duration:.1f} second(s) me kia")
|
|
4081
|
+
return return_value
|
|
4082
|
+
return wrapper
|
|
4083
|
+
timeme = time_me = timeit = time_it
|
|
4084
|
+
timelia = time_lia
|
|
4085
|
+
def internet_access() -> bool:
|
|
4086
|
+
try:
|
|
4087
|
+
requests.get("https://www.google.com", timeout=5)
|
|
4088
|
+
return True
|
|
4089
|
+
except requests.ConnectionError:
|
|
4090
|
+
return False
|
|
4091
|
+
def fetch(url: str = "") -> dict|list:
|
|
4092
|
+
if not url or not "requests" in globals():
|
|
4093
|
+
return {}
|
|
4094
|
+
try:
|
|
4095
|
+
response = requests.get(url, timeout=60)
|
|
4096
|
+
response.raise_for_status()
|
|
4097
|
+
if not (response.status_code >= 200 and response.status_code <= 299):
|
|
4098
|
+
return {}
|
|
4099
|
+
return response.json()
|
|
4100
|
+
except Exception as e:
|
|
4101
|
+
print(f"Error fetching data: {e}")
|
|
4102
|
+
return {}
|
|
4103
|
+
def filepath(to_filename: str) -> str:
|
|
4104
|
+
if not isinstance(to_filename, str):
|
|
4105
|
+
return ""
|
|
4106
|
+
if hasattr(sys, '_MEIPASS'):
|
|
4107
|
+
base = Path(sys._MEIPASS)
|
|
4108
|
+
elif getattr(sys, 'frozen', False):
|
|
4109
|
+
base = Path(sys.executable).parent
|
|
4110
|
+
else:
|
|
4111
|
+
base = Path(__file__).resolve().parent
|
|
4112
|
+
target = to_filename.strip().replace("\\", "/")
|
|
4113
|
+
if target.startswith(".."):
|
|
4114
|
+
if not (hasattr(sys, '_MEIPASS') or getattr(sys, 'frozen', False)):
|
|
4115
|
+
base = base.parent
|
|
4116
|
+
target = target[2:].lstrip("/")
|
|
4117
|
+
else:
|
|
4118
|
+
target = target.lstrip("/")
|
|
4119
|
+
full_path: str = os.path.normpath(os.path.join(str(base), target))
|
|
4120
|
+
# normalize the path, and make it cross-platform
|
|
4121
|
+
return full_path
|
|
4122
|
+
file_path = get_path = to_path = path_to = ki_path = ki_location = ki_directory = filepath
|
|
4123
|
+
def asset(to_filename: str) -> str:
|
|
4124
|
+
path: str = ""
|
|
4125
|
+
try:
|
|
4126
|
+
if either(hasattr(sys, '_MEIPASS'), getattr(sys, 'frozen', False)) and both("_filepaths" in globals(), "PROGRAMS_DIR" in dir(globals().get("_filepaths", {}))):
|
|
4127
|
+
from _filepaths import PROGRAMS_DIR
|
|
4128
|
+
path = os.path.join(PROGRAMS_DIR, to_filename)
|
|
4129
|
+
else:
|
|
4130
|
+
path = to_path(f"../{to_filename}")
|
|
4131
|
+
# SEQUENCE IS MANDATORY
|
|
4132
|
+
fallback_dirs: list[str] = [
|
|
4133
|
+
f"../asset/{to_filename}",
|
|
4134
|
+
f"../assets/{to_filename}",
|
|
4135
|
+
f"../files/{to_filename}",
|
|
4136
|
+
f"../data/{to_filename}",
|
|
4137
|
+
f"../res/{to_filename}",
|
|
4138
|
+
f"../resource/{to_filename}",
|
|
4139
|
+
f"../resources/{to_filename}",
|
|
4140
|
+
f"../____programs____/{to_filename}",
|
|
4141
|
+
f"../____programs____/asset/{to_filename}",
|
|
4142
|
+
f"../____programs____/assets/{to_filename}",
|
|
4143
|
+
f"../____programs____/files/{to_filename}",
|
|
4144
|
+
f"../____programs____/data/{to_filename}",
|
|
4145
|
+
f"../____programs____/res/{to_filename}",
|
|
4146
|
+
f"../____programs____/resource/{to_filename}",
|
|
4147
|
+
f"../____programs____/resources/{to_filename}",
|
|
4148
|
+
f"../_execute/{to_filename}",
|
|
4149
|
+
f"../_execute/asset/{to_filename}",
|
|
4150
|
+
f"../_execute/assets/{to_filename}",
|
|
4151
|
+
f"../_execute/files/{to_filename}",
|
|
4152
|
+
f"../_execute/data/{to_filename}",
|
|
4153
|
+
f"../_execute/res/{to_filename}",
|
|
4154
|
+
f"../_execute/resource/{to_filename}",
|
|
4155
|
+
f"../_execute/resources/{to_filename}",
|
|
4156
|
+
f"./{to_filename}",
|
|
4157
|
+
f"./asset/{to_filename}",
|
|
4158
|
+
f"./assets/{to_filename}",
|
|
4159
|
+
f"./files/{to_filename}",
|
|
4160
|
+
f"./data/{to_filename}",
|
|
4161
|
+
f"./res/{to_filename}",
|
|
4162
|
+
f"./resource/{to_filename}",
|
|
4163
|
+
f"./resources/{to_filename}",
|
|
4164
|
+
f"./____programs____/{to_filename}",
|
|
4165
|
+
f"./____programs____/asset/{to_filename}",
|
|
4166
|
+
f"./____programs____/assets/{to_filename}",
|
|
4167
|
+
f"./____programs____/files/{to_filename}",
|
|
4168
|
+
f"./____programs____/data/{to_filename}",
|
|
4169
|
+
f"./____programs____/res/{to_filename}",
|
|
4170
|
+
f"./____programs____/resource/{to_filename}",
|
|
4171
|
+
f"./____programs____/resources/{to_filename}",
|
|
4172
|
+
f"./_execute/{to_filename}",
|
|
4173
|
+
f"./_execute/asset/{to_filename}",
|
|
4174
|
+
f"./_execute/assets/{to_filename}",
|
|
4175
|
+
f"./_execute/files/{to_filename}",
|
|
4176
|
+
f"./_execute/data/{to_filename}",
|
|
4177
|
+
f"./_execute/res/{to_filename}",
|
|
4178
|
+
f"./_execute/resource/{to_filename}",
|
|
4179
|
+
f"./_execute/resources/{to_filename}"
|
|
4180
|
+
]
|
|
4181
|
+
if not os.path.exists(path):
|
|
4182
|
+
for fallback_dir in fallback_dirs:
|
|
4183
|
+
fallback_dir = to_path(fallback_dir)
|
|
4184
|
+
if os.path.exists(fallback_dir):
|
|
4185
|
+
path = fallback_dir
|
|
4186
|
+
break
|
|
4187
|
+
return os.path.normpath(path)
|
|
4188
|
+
except Exception as e:
|
|
4189
|
+
return ""
|
|
4190
|
+
define_asset = to_asset = get_asset = new_asset = load_asset = naya_asset = asset
|
|
4191
|
+
## belongs at the bottom of KL_Py.py
|
|
4192
|
+
## a helper function for def= operator
|
|
4193
|
+
def get_initial_of(x: Any) -> Any:
|
|
4194
|
+
if not x:
|
|
4195
|
+
return None
|
|
4196
|
+
out: Any
|
|
4197
|
+
match x:
|
|
4198
|
+
case "str":
|
|
4199
|
+
out = ""
|
|
4200
|
+
case "int":
|
|
4201
|
+
out = 0
|
|
4202
|
+
case "flt" | "float" | "dbl" | "double" | "Number" | "nr":
|
|
4203
|
+
# a number is both a float, and int
|
|
4204
|
+
# lets just assume its a float
|
|
4205
|
+
out = 0.0
|
|
4206
|
+
case "bool" | "haal":
|
|
4207
|
+
out = False
|
|
4208
|
+
case "list":
|
|
4209
|
+
out = []
|
|
4210
|
+
case "tuple":
|
|
4211
|
+
out = ()
|
|
4212
|
+
case "set":
|
|
4213
|
+
out = {}
|
|
4214
|
+
case "Arr":
|
|
4215
|
+
out = Arr()
|
|
4216
|
+
case "numlist":
|
|
4217
|
+
out = numlist()
|
|
4218
|
+
case "intlist":
|
|
4219
|
+
out = intlist()
|
|
4220
|
+
case "fltlist":
|
|
4221
|
+
out = fltlist()
|
|
4222
|
+
case "dict" | "obj":
|
|
4223
|
+
out = obj()
|
|
4224
|
+
case _:
|
|
4225
|
+
out = None
|
|
4226
|
+
return out
|
|
4227
|
+
from hindGui import Text
|
|
4228
|
+
# ^ an overwrite fix
|
|
4229
|
+
# ^ needed
|
|
4230
|
+
# a helper constant for platform checks
|
|
4231
|
+
WINDOWS: Final[str] = "nt"
|
|
4232
|
+
INTERNAL_JSON: Final[str] = to_asset("json/")
|
|
4233
|
+
JSONS: Final[str] = INTERNAL_JSON
|
|
4234
|
+
def json_load_internal(filename: str) -> dict | list:
|
|
4235
|
+
if not isinstance(filename, str) or not filename.strip():
|
|
4236
|
+
return {}
|
|
4237
|
+
return json_load(to_asset(f"json/{filename}"))
|
|
4238
|
+
load_internal_json = loadinternaljson = jsonloadinternal = json_load_internal
|
|
4239
|
+
colors = COLORS = {}
|
|
4240
|
+
pakistani_names = PAKISTANI_NAMES = {}
|
|
4241
|
+
try:
|
|
4242
|
+
colors = COLORS = load_internal_json("colors")
|
|
4243
|
+
pakistani_names = PAKISTANI_NAMES = load_internal_json("pakistani_names")
|
|
4244
|
+
except Exception:
|
|
4245
|
+
...
|
|
4246
|
+
|
|
4247
|
+
|
|
4248
|
+
|
|
4249
|
+
|
|
4250
|
+
if __name__ == "__main__":
|
|
4251
|
+
print(Int("100", 2))
|
|
4252
|
+
print(Flt("2.22"))
|
|
4253
|
+
print(Int(2.22))
|
|
4254
|
+
print(Flt(2.22))
|
|
4255
|
+
print(Int(2))
|
|
4256
|
+
print(Flt(2))
|
|
4257
|
+
dictionary: obj = obj(key="value")
|
|
4258
|
+
cloned = clone(dictionary)
|
|
4259
|
+
cloned.key = 4
|
|
4260
|
+
print(dictionary.entries())
|
|
4261
|
+
print(cloned.entries())
|
|
4262
|
+
name: lafz = "Misty"
|
|
4263
|
+
print(name)
|
|
4264
|
+
x: num = 4
|
|
4265
|
+
print(x)
|
|
4266
|
+
printf("$name dont! You are, but a $10+5-8 -year-old kid. $x")
|
|
4267
|
+
print(isstr(""))
|
|
4268
|
+
print(isint(3))
|
|
4269
|
+
print(isflt(""))
|
|
4270
|
+
print(isstr(None))
|
|
4271
|
+
print(isstr(None))
|
|
4272
|
+
print(isstr(None))
|
|
4273
|
+
print(isstr(None))
|
|
4274
|
+
print(isstr(None))
|
|
4275
|
+
print(isstr(None))
|
|
4276
|
+
print(isfunc(internet_access))
|
|
4277
|
+
print(flatten([1, [2, [3, 4, [5, 6]]]]))
|
|
4278
|
+
print(remove_duplicates([1, 3, 1, 5, 6, 3, 7, 8, 9]))
|
|
4279
|
+
print(kism(7.5))
|
|
4280
|
+
print(he_kism(7.5, float))
|
|
4281
|
+
printf("hi, $75000.77778:,")
|
|
4282
|
+
x = 12345.6789
|
|
4283
|
+
print(f("$x", "$x:.2f", f"{x:,}", f"{x:,.2f}"))
|
|
4284
|
+
array = intlist(1.4, 2.9, 3.5)
|
|
4285
|
+
array2 = fltlist(2, 4, 6)
|
|
4286
|
+
result = array * array2
|
|
4287
|
+
print(result)
|
|
4288
|
+
nlist: numlist = numlist(1, 3, 5, 7)
|
|
4289
|
+
print(nlist.push([9, 11]))
|
|
4290
|
+
array = Arr([1.2, 3, 5, 6, None, ""], fixed=False)
|
|
4291
|
+
array.me_dalo("x")
|
|
4292
|
+
array.me_dalo("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0 xxx")
|
|
4293
|
+
print(f"{array=}")
|
|
4294
|
+
#pprint({"name": "Mike", "age": 17, "hobbies": ["horse riding", "country music", "farming"]})
|
|
4295
|
+
print(Msg, Message, Error, Err)
|
|
4296
|
+
@auto_id
|
|
4297
|
+
@auto_class
|
|
4298
|
+
class Book:
|
|
4299
|
+
name: str
|
|
4300
|
+
author: str
|
|
4301
|
+
release: int
|
|
4302
|
+
book1: Book = Book("To Kill A MockingBird", "Anonymous", 2003)
|
|
4303
|
+
book2: Book = Book("The Subtle Art of Not Caring", "Mark Manson", 2007)
|
|
4304
|
+
print(book1.name, book1.author, book1.release, book1.__id__, book1.__shanakht__)
|
|
4305
|
+
print(book1.name, book1.author, book1.release, book1.__id__, book1.__shanakht__)
|
|
4306
|
+
print(book2.name, book2.author, book2.release, book2.__id__, book2.__shanakht__)
|
|
4307
|
+
print(book2.name, book2.author, book2.release, book2.__id__, book2.__shanakht__)
|
|
4308
|
+
print(belongs_to(book1, Book))
|
|
4309
|
+
print(isinstance_each([IOError, OSError], (Exception | BaseException)))
|
|
4310
|
+
print(hissa(None, ["hello world", None]))
|
|
4311
|
+
print(belongs_to(IOError | OSError, Exception))
|
|
4312
|
+
print(chuno(rng(1, 10), koi=2))
|
|
4313
|
+
my_dict: dict[str, dict[str, str] | int] = {"name": {"first": "Mike", "last": "Dawson"}, "age": 22000}
|
|
4314
|
+
from _klang_builtins import cust_print
|
|
4315
|
+
cust_print(my_dict)
|
|
4316
|
+
print(deep_get(my_dict, "first"))
|
|
4317
|
+
dt: Date = Date("2.44 am, Jan 24, 2002")
|
|
4318
|
+
cust_print(dt.day_name(), dont_format_nums=True)
|
|
4319
|
+
cust_print(dt.month_name(), dont_format_nums=True)
|
|
4320
|
+
cust_print(dt.year(), dont_format_nums=True)
|
|
4321
|
+
cust_print(dt.day_name(True), dont_format_nums=True)
|
|
4322
|
+
cust_print(dt.month_name(True), dont_format_nums=True)
|
|
4323
|
+
cust_print(dt.year(True), dont_format_nums=True)
|
|
4324
|
+
dt.update(year=2021)
|
|
4325
|
+
cust_print(dt.year(True), dont_format_nums=True)
|
|
4326
|
+
print(Date("Jun 15 2026").is_weekend())
|
|
4327
|
+
print(Date("Jun 15 2026").is_weekday())
|
|
4328
|
+
print(obj(my_dict).ke("Name").mese("First", default="Anonymous"))
|
|
4329
|
+
print(rng(10, 100, 10) [4-1])
|
|
4330
|
+
print(Text, Bolo, Text == Bolo)
|
|
4331
|
+
print(has_match("P@$$w0rd", STRICT_PWD_RE))
|
|
4332
|
+
print(split_into_words("what a beautifully-crafted fun art, 'tisnit?"))
|
|
4333
|
+
print(is_mail("abbaskhurram255@gmail.com"))
|
|
4334
|
+
print(has_mail("abbaskhurram255@gmail.com 03012965459"))
|
|
4335
|
+
print(catch_mail("abbaskhurram255@gmail.com 03012965459 abbaskhurram255@yahoo.com"))
|
|
4336
|
+
print(catch_mail("abbaskhurram255@gmail.com 03012965459"))
|
|
4337
|
+
print(catch_phone("abbaskhurram255@gmail.com 03012965459 abbaskhurram255@yahoo.com"))
|
|
4338
|
+
print(is_pin(1535))
|
|
4339
|
+
print(is_pin(153))
|
|
4340
|
+
print(is_pin("1535"))
|
|
4341
|
+
print(is_pin("153"))
|
|
4342
|
+
print(ishex("#68fafe"))
|
|
4343
|
+
countries: dict = load_json(r"json/countries.json")
|
|
4344
|
+
print(countries)
|
|
4345
|
+
arr = (1, 3.8, 7)
|
|
4346
|
+
arr = _map(arr, str, lambda x: type(x) != float)
|
|
4347
|
+
print(arr)
|
|
4348
|
+
print(obj(my_dict).floor_key("NA"))
|
|
4349
|
+
print(ltype(None))
|
|
4350
|
+
print(ltype(Date()))
|
|
4351
|
+
print(ltype(obj({1: "Lucien", 2: lambda: ...})))
|
|
4352
|
+
print(ltype({"x": 1, "y": lambda: ...}))
|
|
4353
|
+
print(ltype({"x": 1, "y": lambda: ...}))
|
|
4354
|
+
print(ltype({"y": lambda: ...}))
|
|
4355
|
+
print(ltype({"y": lambda: ...}))
|
|
4356
|
+
print(ltype({"y": Book("x", "y", 2000)}))
|
|
4357
|
+
print(ltype({"y": Book("x", "y", 2000)}))
|
|
4358
|
+
print(rng("a", "z", shamil=Nahi))
|
|
4359
|
+
print(rng(1, 10, inclusive=globals().get('shamil'.strip().replace(' ', '_').upper(), True)))
|
|
4360
|
+
print(rng(1, 10, step=int('2' or '1'), inclusive=globals().get('shaamil akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4361
|
+
print(rng(1, 10, step=int('2' or '1'), inclusive=globals().get('bager akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4362
|
+
print(rng(1, 10, step=int('' or '1'), inclusive=globals().get('bager_akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4363
|
+
print(rng(20, step=.5, inclusive=globals().get(''.strip().replace(' ', '_').upper(), True)))
|
|
4364
|
+
|
|
4365
|
+
# sucks >>
|
|
4366
|
+
print("\n\nsucks:")
|
|
4367
|
+
print(rng(20))
|
|
4368
|
+
print("\n\n")
|
|
4369
|
+
|
|
4370
|
+
print(rng(1, 10, step=float('2' or '1'), inclusive=globals().get('shaamil akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4371
|
+
print(rng(1, 10, step=float('2' or '1'), inclusive=globals().get('shaamil akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4372
|
+
print(rng(1, 10, step=float('' or '1'), inclusive=globals().get('bager akhri'.strip().replace(' ', '_').upper(), True)))
|
|
4373
|
+
print(rng(1, 10, step=float('.5' or '1'), inclusive=globals().get(''.strip().replace(' ', '_').upper(), True)))
|
|
4374
|
+
|
|
4375
|
+
print(rng('a', 'y', step=.5))
|
|
4376
|
+
print(rng('w', 'y'))
|
|
4377
|
+
print(rng(10))
|
|
4378
|
+
print(rng(10, inclusive=FORCE_INCLUSIVE, step=float('2.5')))
|
|
4379
|
+
|
|
4380
|
+
print(he_parsable_num("5.7"))
|
|
4381
|
+
print(Flt("5.7"))
|
|
4382
|
+
print(Int("5.7"))
|
|
4383
|
+
|
|
4384
|
+
print(rng("b", "z", reverse=REVERSED, step=2))
|
|
4385
|
+
print(rng(1, 44, step=float('5' or '1'), inclusive=globals().get('shamil akhri'.strip().replace(' ', '_').upper(), True), reverse=globals().get('nahi reverse'.strip().replace(' ', '_').upper(), False)))
|
|
4386
|
+
print(rng(10, step=float('2' or '1'), inclusive=globals().get('shamil akhri'.strip().replace(' ', '_').upper(), True), reverse=globals().get('reverse'.strip().replace(' ', '_').upper(), False)))
|
|
4387
|
+
print(rng(10, step=float('5' or '1'), inclusive=globals().get('zabardasti shamil akhri'.strip().replace(' ', '_').upper(), True), reverse=globals().get('reverse'.strip().replace(' ', '_').upper(), False)))
|
|
4388
|
+
|
|
4389
|
+
print(rng('a', 'y', step=float('2' or '1'), inclusive=globals().get('shamil akhri'.strip().replace(' ', '_').upper(), True), reverse=globals().get(''.strip().replace(' ', '_').upper(), False)))
|
|
4390
|
+
arr = rng(1, 10)
|
|
4391
|
+
shuffle_inplace(arr)
|
|
4392
|
+
print(arr)
|
|
4393
|
+
colors["sub"] = {"sub2": {"sub3a": 15, "sub3b": 20, 8.3: 8.0}}
|
|
4394
|
+
print(safe_get(colors, 8, default="Couldn't find"))
|
|
4395
|
+
print(colors.sub.sub3B)
|
|
4396
|
+
|
|
4397
|
+
print(Date("2026-07-22 12.01 am").day_nr())
|
|
4398
|
+
print(Date("2026-07-22 12.01 am").time_and_day())
|
|
4399
|
+
print(Date("2002-07-22 12.01 am").yr(2004).d(21).d(), nahi_format_nums=Han)
|
|
4400
|
+
print(Date.day_today())
|