xulbux 1.6.5__tar.gz → 1.6.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xulbux might be problematic. Click here for more details.
- {xulbux-1.6.5/src/xulbux.egg-info → xulbux-1.6.6}/PKG-INFO +3 -1
- {xulbux-1.6.5 → xulbux-1.6.6}/pyproject.toml +7 -5
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/__init__.py +1 -1
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/_cli_.py +9 -9
- xulbux-1.6.6/src/xulbux/_consts_.py +158 -0
- xulbux-1.6.6/src/xulbux/xx_code.py +100 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_color.py +27 -55
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_console.py +154 -106
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_data.py +176 -125
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_env_path.py +1 -5
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_format_codes.py +26 -37
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_json.py +2 -5
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_path.py +5 -5
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_regex.py +18 -20
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_string.py +23 -76
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_system.py +5 -13
- {xulbux-1.6.5 → xulbux-1.6.6/src/xulbux.egg-info}/PKG-INFO +3 -1
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/requires.txt +2 -0
- xulbux-1.6.6/tests/test_console_info.py +37 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_data.py +2 -2
- xulbux-1.6.5/src/xulbux/_consts_.py +0 -145
- xulbux-1.6.5/src/xulbux/xx_code.py +0 -105
- xulbux-1.6.5/tests/test_console_info.py +0 -19
- {xulbux-1.6.5 → xulbux-1.6.6}/LICENSE +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/README.md +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/setup.cfg +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_file.py +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/SOURCES.txt +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/dependency_links.txt +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/entry_points.txt +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/top_level.txt +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_color.py +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_color_types.py +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_env_vars.py +0 -0
- {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_format_codes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: xulbux
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.6
|
|
4
4
|
Summary: A library which includes a lot of really helpful functions.
|
|
5
5
|
Author-email: XulbuX <xulbux.real@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -45,6 +45,7 @@ Description-Content-Type: text/markdown
|
|
|
45
45
|
License-File: LICENSE
|
|
46
46
|
Requires-Dist: keyboard>=0.13.5
|
|
47
47
|
Requires-Dist: mouse>=0.7.1
|
|
48
|
+
Requires-Dist: prompt_toolkit>=3.0.41
|
|
48
49
|
Requires-Dist: pyperclip>=1.9.0
|
|
49
50
|
Requires-Dist: regex>=2023.10.3
|
|
50
51
|
Provides-Extra: dev
|
|
@@ -52,6 +53,7 @@ Requires-Dist: pytest>=7.4.2; extra == "dev"
|
|
|
52
53
|
Requires-Dist: black>=23.7.0; extra == "dev"
|
|
53
54
|
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
54
55
|
Requires-Dist: flake8>=6.1.0; extra == "dev"
|
|
56
|
+
Requires-Dist: flake8-pyproject>=1.2.3; extra == "dev"
|
|
55
57
|
|
|
56
58
|
# **$\color{#8085FF}\Huge\textsf{XulbuX}$**
|
|
57
59
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xulbux"
|
|
7
|
-
version = "1.6.
|
|
7
|
+
version = "1.6.6"
|
|
8
8
|
authors = [{ name = "XulbuX", email = "xulbux.real@gmail.com" }]
|
|
9
9
|
description = "A library which includes a lot of really helpful functions."
|
|
10
10
|
readme = "README.md"
|
|
@@ -13,6 +13,7 @@ requires-python = ">=3.10.0"
|
|
|
13
13
|
dependencies = [
|
|
14
14
|
"keyboard>=0.13.5",
|
|
15
15
|
"mouse>=0.7.1",
|
|
16
|
+
"prompt_toolkit>=3.0.41",
|
|
16
17
|
"pyperclip>=1.9.0",
|
|
17
18
|
"regex>=2023.10.3",
|
|
18
19
|
]
|
|
@@ -21,6 +22,7 @@ optional-dependencies = { dev = [
|
|
|
21
22
|
"black>=23.7.0",
|
|
22
23
|
"isort>=5.12.0",
|
|
23
24
|
"flake8>=6.1.0",
|
|
25
|
+
"flake8-pyproject>=1.2.3",
|
|
24
26
|
] }
|
|
25
27
|
classifiers = [
|
|
26
28
|
"Intended Audience :: Developers",
|
|
@@ -103,11 +105,11 @@ use_parentheses = true
|
|
|
103
105
|
ensure_newline_before_comments = true
|
|
104
106
|
|
|
105
107
|
[tool.flake8]
|
|
108
|
+
max-complexity = 12
|
|
106
109
|
max-line-length = 127
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
per-file-ignores = ["__init__.py:F401,F403"]
|
|
110
|
+
select = ["E", "F", "W", "C90"]
|
|
111
|
+
extend-ignore = ["E203", "E266", "W503"]
|
|
112
|
+
per-file-ignores = ["__init__.py:F403,F405"]
|
|
111
113
|
|
|
112
114
|
[tool.setuptools]
|
|
113
115
|
packages = ["xulbux"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from . import __version__
|
|
2
|
-
from ._consts_ import
|
|
2
|
+
from ._consts_ import COLOR
|
|
3
3
|
from .xx_format_codes import FormatCodes
|
|
4
4
|
from .xx_console import Console
|
|
5
5
|
|
|
@@ -7,20 +7,20 @@ from .xx_console import Console
|
|
|
7
7
|
def help_command():
|
|
8
8
|
"""Show some info about the library, with a brief explanation of how to use it."""
|
|
9
9
|
color = {
|
|
10
|
-
"lib":
|
|
11
|
-
"import":
|
|
12
|
-
"class":
|
|
13
|
-
"types":
|
|
14
|
-
"punctuators":
|
|
10
|
+
"lib": COLOR.ice,
|
|
11
|
+
"import": COLOR.red,
|
|
12
|
+
"class": COLOR.lavender,
|
|
13
|
+
"types": COLOR.lightblue,
|
|
14
|
+
"punctuators": COLOR.darkgray,
|
|
15
15
|
}
|
|
16
16
|
FormatCodes.print(
|
|
17
17
|
rf""" [_|b|#7075FF] __ __
|
|
18
18
|
[b|#7075FF] _ __ __ __/ / / /_ __ ___ __
|
|
19
19
|
[b|#7075FF] | |/ // / / / / / __ \/ / / | |/ /
|
|
20
20
|
[b|#7075FF] > , </ /_/ / /_/ /_/ / /_/ /> , <
|
|
21
|
-
[b|#7075FF]/_/|_|\____/\__/\____/\____//_/|_| [*|BG:{
|
|
21
|
+
[b|#7075FF]/_/|_|\____/\__/\____/\____//_/|_| [*|BG:{COLOR.gray}|#000] v[b]{__version__} [*]
|
|
22
22
|
|
|
23
|
-
[i|{
|
|
23
|
+
[i|{COLOR.coral}]A TON OF COOL FUNCTIONS, YOU NEED![*]
|
|
24
24
|
|
|
25
25
|
[b|#75A2FF]Usage:[*]
|
|
26
26
|
[{color['punctuators']}]# GENERAL LIBRARY[*]
|
|
@@ -48,6 +48,6 @@ def help_command():
|
|
|
48
48
|
[_]
|
|
49
49
|
[dim](Press any key to exit...)
|
|
50
50
|
""",
|
|
51
|
-
default_color=
|
|
51
|
+
default_color=COLOR.text
|
|
52
52
|
)
|
|
53
53
|
Console.pause_exit(pause=True)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import TypeAlias
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
FormattableString: TypeAlias = str
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class COLOR:
|
|
10
|
+
"""Color presets used in the XulbuX library."""
|
|
11
|
+
|
|
12
|
+
text = "#A5D6FF"
|
|
13
|
+
white = "#F1F2FF"
|
|
14
|
+
lightgray = "#B6B7C0"
|
|
15
|
+
gray = "#7B7C8D"
|
|
16
|
+
darkgray = "#67686C"
|
|
17
|
+
black = "#202125"
|
|
18
|
+
red = "#FF606A"
|
|
19
|
+
coral = "#FF7069"
|
|
20
|
+
orange = "#FF876A"
|
|
21
|
+
tangerine = "#FF9962"
|
|
22
|
+
gold = "#FFAF60"
|
|
23
|
+
yellow = "#FFD260"
|
|
24
|
+
green = "#7EE787"
|
|
25
|
+
teal = "#50EAAF"
|
|
26
|
+
cyan = "#3EDEE6"
|
|
27
|
+
ice = "#77DBEF"
|
|
28
|
+
lightblue = "#60AAFF"
|
|
29
|
+
blue = "#8085FF"
|
|
30
|
+
lavender = "#9B7DFF"
|
|
31
|
+
purple = "#AD68FF"
|
|
32
|
+
magenta = "#C860FF"
|
|
33
|
+
pink = "#F162EF"
|
|
34
|
+
rose = "#FF609F"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class _AllTextCharacters:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class CHARS:
|
|
43
|
+
"""Strings with only certain text characters."""
|
|
44
|
+
|
|
45
|
+
# CODE TO SIGNAL, ALL CHARACTERS ARE ALLOWED
|
|
46
|
+
all = _AllTextCharacters
|
|
47
|
+
|
|
48
|
+
# DIGIT SETS
|
|
49
|
+
digits: str = "0123456789"
|
|
50
|
+
float_digits: str = digits + "."
|
|
51
|
+
hex_digits: str = digits + "#abcdefABCDEF"
|
|
52
|
+
|
|
53
|
+
# LETTER CATEGORIES
|
|
54
|
+
lowercase: str = "abcdefghijklmnopqrstuvwxyz"
|
|
55
|
+
lowercase_extended: str = lowercase + "äëïöüÿàèìòùáéíóúýâêîôûãñõåæç"
|
|
56
|
+
uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
57
|
+
uppercase_extended: str = uppercase + "ÄËÏÖÜÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÅÆÇß"
|
|
58
|
+
|
|
59
|
+
# COMBINED LETTER SETS
|
|
60
|
+
letters: str = lowercase + uppercase
|
|
61
|
+
letters_extended: str = lowercase_extended + uppercase_extended
|
|
62
|
+
|
|
63
|
+
# ASCII sets
|
|
64
|
+
special_ascii: str = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
|
65
|
+
special_ascii_extended: str = special_ascii + "ø£Ø×ƒªº¿®¬½¼¡«»░▒▓│┤©╣║╗╝¢¥┐└┴┬├─┼╚╔╩╦╠═╬¤ðÐı┘┌█▄¦▀µþÞ¯´≡±‗¾¶§÷¸°¨·¹³²■ "
|
|
66
|
+
standard_ascii: str = special_ascii + digits + letters
|
|
67
|
+
full_ascii: str = special_ascii_extended + digits + letters_extended
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ANSI:
|
|
71
|
+
"""Constants and class-methods for use of ANSI escape codes."""
|
|
72
|
+
|
|
73
|
+
escaped_char: str = "\\x1b"
|
|
74
|
+
CHAR = char = "\x1b"
|
|
75
|
+
START = start = "["
|
|
76
|
+
SEP = sep = ";"
|
|
77
|
+
END = end = "m"
|
|
78
|
+
default_color_modifiers: dict[str, str] = {"lighten": "+l", "darken": "-d"}
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def seq(cls, parts: int = 1) -> str:
|
|
82
|
+
"""Generate an ANSI sequence with `parts` amount of placeholders."""
|
|
83
|
+
return cls.CHAR + cls.START + cls.SEP.join(["{}" for _ in range(parts)]) + cls.END
|
|
84
|
+
|
|
85
|
+
seq_color: FormattableString = CHAR + START + "38" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
|
|
86
|
+
seq_bg_color: FormattableString = CHAR + START + "48" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
|
|
87
|
+
|
|
88
|
+
color_map: list[str] = [
|
|
89
|
+
########### DEFAULT CONSOLE COLOR NAMES ############
|
|
90
|
+
"black",
|
|
91
|
+
"red",
|
|
92
|
+
"green",
|
|
93
|
+
"yellow",
|
|
94
|
+
"blue",
|
|
95
|
+
"magenta",
|
|
96
|
+
"cyan",
|
|
97
|
+
"white",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
codes_map: dict[str | tuple[str, ...], int] = {
|
|
101
|
+
################# SPECIFIC RESETS ##################
|
|
102
|
+
"_": 0,
|
|
103
|
+
("_bold", "_b"): 22,
|
|
104
|
+
("_dim", "_d"): 22,
|
|
105
|
+
("_italic", "_i"): 23,
|
|
106
|
+
("_underline", "_u"): 24,
|
|
107
|
+
("_double-underline", "_du"): 24,
|
|
108
|
+
("_inverse", "_invert", "_in"): 27,
|
|
109
|
+
("_hidden", "_hide", "_h"): 28,
|
|
110
|
+
("_strikethrough", "_s"): 29,
|
|
111
|
+
("_color", "_c"): 39,
|
|
112
|
+
("_background", "_bg"): 49,
|
|
113
|
+
################### TEXT STYLES ####################
|
|
114
|
+
("bold", "b"): 1,
|
|
115
|
+
("dim", "d"): 2,
|
|
116
|
+
("italic", "i"): 3,
|
|
117
|
+
("underline", "u"): 4,
|
|
118
|
+
("inverse", "invert", "in"): 7,
|
|
119
|
+
("hidden", "hide", "h"): 8,
|
|
120
|
+
("strikethrough", "s"): 9,
|
|
121
|
+
("double-underline", "du"): 21,
|
|
122
|
+
################## DEFAULT COLORS ##################
|
|
123
|
+
"black": 30,
|
|
124
|
+
"red": 31,
|
|
125
|
+
"green": 32,
|
|
126
|
+
"yellow": 33,
|
|
127
|
+
"blue": 34,
|
|
128
|
+
"magenta": 35,
|
|
129
|
+
"cyan": 36,
|
|
130
|
+
"white": 37,
|
|
131
|
+
############## BRIGHT DEFAULT COLORS ###############
|
|
132
|
+
"br:black": 90,
|
|
133
|
+
"br:red": 91,
|
|
134
|
+
"br:green": 92,
|
|
135
|
+
"br:yellow": 93,
|
|
136
|
+
"br:blue": 94,
|
|
137
|
+
"br:magenta": 95,
|
|
138
|
+
"br:cyan": 96,
|
|
139
|
+
"br:white": 97,
|
|
140
|
+
############ DEFAULT BACKGROUND COLORS #############
|
|
141
|
+
"bg:black": 40,
|
|
142
|
+
"bg:red": 41,
|
|
143
|
+
"bg:green": 42,
|
|
144
|
+
"bg:yellow": 43,
|
|
145
|
+
"bg:blue": 44,
|
|
146
|
+
"bg:magenta": 45,
|
|
147
|
+
"bg:cyan": 46,
|
|
148
|
+
"bg:white": 47,
|
|
149
|
+
######### BRIGHT DEFAULT BACKGROUND COLORS #########
|
|
150
|
+
"bg:br:black": 100,
|
|
151
|
+
"bg:br:red": 101,
|
|
152
|
+
"bg:br:green": 102,
|
|
153
|
+
"bg:br:yellow": 103,
|
|
154
|
+
"bg:br:blue": 104,
|
|
155
|
+
"bg:br:magenta": 105,
|
|
156
|
+
"bg:br:cyan": 106,
|
|
157
|
+
"bg:br:white": 107,
|
|
158
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from .xx_string import String
|
|
2
|
+
from .xx_regex import Regex
|
|
3
|
+
from .xx_data import Data
|
|
4
|
+
|
|
5
|
+
import regex as _rx
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Code:
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def add_indent(code: str, indent: int) -> str:
|
|
12
|
+
"""Adds `indent` spaces at the beginning of each line."""
|
|
13
|
+
indented_lines = [" " * indent + line for line in code.splitlines()]
|
|
14
|
+
return "\n".join(indented_lines)
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def get_tab_spaces(code: str) -> int:
|
|
18
|
+
"""Will try to get the amount of spaces used for indentation."""
|
|
19
|
+
code_lines = String.get_lines(code, remove_empty_lines=True)
|
|
20
|
+
indents = [len(line) - len(line.lstrip()) for line in code_lines]
|
|
21
|
+
non_zero_indents = [i for i in indents if i > 0]
|
|
22
|
+
return min(non_zero_indents) if non_zero_indents else 0
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def change_tab_size(code: str, new_tab_size: int, remove_empty_lines: bool = False) -> str:
|
|
26
|
+
"""Replaces all tabs with `new_tab_size` spaces.\n
|
|
27
|
+
----------------------------------------------------------------------------------
|
|
28
|
+
If `remove_empty_lines` is `True`, empty lines will be removed in the process."""
|
|
29
|
+
code_lines = String.get_lines(code, remove_empty_lines=True)
|
|
30
|
+
lines = code_lines if remove_empty_lines else String.get_lines(code)
|
|
31
|
+
tab_spaces = Code.get_tab_spaces(code)
|
|
32
|
+
if (tab_spaces == new_tab_size) or tab_spaces == 0:
|
|
33
|
+
if remove_empty_lines:
|
|
34
|
+
return "\n".join(code_lines)
|
|
35
|
+
return code
|
|
36
|
+
result = []
|
|
37
|
+
for line in lines:
|
|
38
|
+
stripped = line.lstrip()
|
|
39
|
+
indent_level = (len(line) - len(stripped)) // tab_spaces
|
|
40
|
+
new_indent = " " * (indent_level * new_tab_size)
|
|
41
|
+
result.append(new_indent + stripped)
|
|
42
|
+
return "\n".join(result)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def get_func_calls(code: str) -> list:
|
|
46
|
+
"""Will try to get all function calls and return them as a list."""
|
|
47
|
+
funcs = _rx.findall(r"(?i)" + Regex.func_call(), code)
|
|
48
|
+
nested_func_calls = []
|
|
49
|
+
for _, func_attrs in funcs:
|
|
50
|
+
nested_calls = _rx.findall(r"(?i)" + Regex.func_call(), func_attrs)
|
|
51
|
+
if nested_calls:
|
|
52
|
+
nested_func_calls.extend(nested_calls)
|
|
53
|
+
return Data.remove_duplicates(funcs + nested_func_calls)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def is_js(code: str, funcs: list = ["__", "$t", "$lang"]) -> bool:
|
|
57
|
+
"""Will check if the code is very likely to be JavaScript."""
|
|
58
|
+
funcs = "|".join(funcs)
|
|
59
|
+
js_pattern = _rx.compile(
|
|
60
|
+
Regex.outside_strings(
|
|
61
|
+
r"""^(?:
|
|
62
|
+
(\$[\w_]+)\s* # JQUERY-STYLE VARIABLES
|
|
63
|
+
|(\$[\w_]+\s*\() # JQUERY-STYLE FUNCTION CALLS
|
|
64
|
+
|((""" + funcs + r")" + Regex.brackets("()") + r"""\s*) # PREDEFINED FUNCTION CALLS
|
|
65
|
+
|(\bfunction\s*\() # FUNCTION DECLARATIONS
|
|
66
|
+
|(\b(var|let|const)\s+[\w_]+\s*=) # VARIABLE DECLARATIONS
|
|
67
|
+
|(\b(if|for|while|switch)\s*\() # CONTROL STRUCTURES
|
|
68
|
+
|(\b(return|throw)\s+) # RETURN OR THROW STATEMENTS
|
|
69
|
+
|(\bnew\s+[\w_]+\() # OBJECT INSTANTIATION
|
|
70
|
+
|(\b[\w_]+\s*=>\s*{) # ARROW FUNCTIONS
|
|
71
|
+
|(\b(true|false|null|undefined)\b) # JAVASCRIPT LITERALS
|
|
72
|
+
|(\b(document|window|console)\.) # BROWSER OBJECTS
|
|
73
|
+
|(\b[\w_]+\.(forEach|map|filter|reduce)\() # ARRAY METHODS
|
|
74
|
+
|(/[^/\n\r]*?/[gimsuy]*) # REGULAR EXPRESSIONS
|
|
75
|
+
|(===|!==|\+\+|--|\|\||&&) # JAVASCRIPT-SPECIFIC OPERATORS
|
|
76
|
+
|(\bclass\s+[\w_]+) # CLASS DECLARATIONS
|
|
77
|
+
|(\bimport\s+.*?from\s+) # IMPORT STATEMENTS
|
|
78
|
+
|(\bexport\s+(default\s+)?) # EXPORT STATEMENTS
|
|
79
|
+
|(\basync\s+function) # ASYNC FUNCTIONS
|
|
80
|
+
|(\bawait\s+) # AWAIT KEYWORD
|
|
81
|
+
|(\btry\s*{) # TRY-CATCH BLOCKS
|
|
82
|
+
|(\bcatch\s*\()
|
|
83
|
+
|(\bfinally\s*{)
|
|
84
|
+
|(\byield\s+) # GENERATOR FUNCTIONS
|
|
85
|
+
|(\[.*?\]\s*=) # DESTRUCTURING ASSIGNMENT
|
|
86
|
+
|(\.\.\.) # SPREAD OPERATOR
|
|
87
|
+
|(==|!=|>=|<=|>|<) # COMPARISON OPERATORS
|
|
88
|
+
|(\+=|-=|\*=|/=|%=|\*\*=) # COMPOUND ASSIGNMENT OPERATORS
|
|
89
|
+
|(\+|-|\*|/|%|\*\*) # ARITHMETIC OPERATORS
|
|
90
|
+
|(&|\||\^|~|<<|>>|>>>) # BITWISE OPERATORS
|
|
91
|
+
|(\?|:) # TERNARY OPERATOR
|
|
92
|
+
|(\bin\b) # IN OPERATOR
|
|
93
|
+
|(\binstanceof\b) # INSTANCEOF OPERATOR
|
|
94
|
+
|(\bdelete\b) # DELETE OPERATOR
|
|
95
|
+
|(\btypeof\b) # TYPEOF OPERATOR
|
|
96
|
+
|(\bvoid\b) # VOID OPERATOR
|
|
97
|
+
)[\s\S]*$"""
|
|
98
|
+
), _rx.VERBOSE | _rx.IGNORECASE
|
|
99
|
+
)
|
|
100
|
+
return bool(js_pattern.fullmatch(code))
|
|
@@ -33,6 +33,7 @@ The `Color` class, which contains all sorts of different color-related methods:
|
|
|
33
33
|
|
|
34
34
|
from .xx_regex import Regex
|
|
35
35
|
|
|
36
|
+
from typing import Optional
|
|
36
37
|
import re as _re
|
|
37
38
|
|
|
38
39
|
|
|
@@ -79,13 +80,13 @@ class rgba:
|
|
|
79
80
|
return 3 if self.a is None else 4
|
|
80
81
|
|
|
81
82
|
def __iter__(self) -> iter:
|
|
82
|
-
return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))
|
|
83
|
+
return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))
|
|
83
84
|
|
|
84
85
|
def __dict__(self) -> dict:
|
|
85
86
|
return self.dict()
|
|
86
87
|
|
|
87
88
|
def __getitem__(self, index: int) -> int:
|
|
88
|
-
return ((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))[index]
|
|
89
|
+
return ((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))[index]
|
|
89
90
|
|
|
90
91
|
def __repr__(self) -> str:
|
|
91
92
|
return f'rgba({self.r}, {self.g}, {self.b}{"" if self.a is None else f", {self.a}"})'
|
|
@@ -183,13 +184,7 @@ class rgba:
|
|
|
183
184
|
if additive_alpha:
|
|
184
185
|
self.a = max(0, min(1, (self_a * (2 - ratio)) + (other_a * ratio)))
|
|
185
186
|
else:
|
|
186
|
-
self.a = max(
|
|
187
|
-
0,
|
|
188
|
-
min(
|
|
189
|
-
1,
|
|
190
|
-
(self_a * (1 - (ratio / 2))) + (other_a * (ratio / 2)),
|
|
191
|
-
),
|
|
192
|
-
)
|
|
187
|
+
self.a = max(0, min(1, (self_a * (1 - (ratio / 2))) + (other_a * (ratio / 2))))
|
|
193
188
|
else:
|
|
194
189
|
self.a = None
|
|
195
190
|
return rgba(self.r, self.g, self.b, None if none_alpha else self.a, _validate=False)
|
|
@@ -282,13 +277,13 @@ class hsla:
|
|
|
282
277
|
return 3 if self.a is None else 4
|
|
283
278
|
|
|
284
279
|
def __iter__(self) -> iter:
|
|
285
|
-
return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))
|
|
280
|
+
return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))
|
|
286
281
|
|
|
287
282
|
def __dict__(self) -> dict:
|
|
288
283
|
return self.dict()
|
|
289
284
|
|
|
290
285
|
def __getitem__(self, index: int) -> int:
|
|
291
|
-
return ((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))[index]
|
|
286
|
+
return ((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))[index]
|
|
292
287
|
|
|
293
288
|
def __repr__(self) -> str:
|
|
294
289
|
return f'hsla({self.h}, {self.s}, {self.l}{"" if self.a is None else f", {self.a}"})'
|
|
@@ -508,17 +503,15 @@ class hexa:
|
|
|
508
503
|
return 3 if self.a is None else 4
|
|
509
504
|
|
|
510
505
|
def __iter__(self) -> iter:
|
|
511
|
-
return iter(
|
|
512
|
-
|
|
513
|
-
)
|
|
506
|
+
return iter((f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}")
|
|
507
|
+
+ (() if self.a is None else (f"{int(self.a * 255):02X}", )))
|
|
514
508
|
|
|
515
509
|
def __dict__(self) -> dict:
|
|
516
510
|
return self.dict()
|
|
517
511
|
|
|
518
512
|
def __getitem__(self, index: int) -> int:
|
|
519
|
-
return (
|
|
520
|
-
|
|
521
|
-
)[index]
|
|
513
|
+
return ((f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else
|
|
514
|
+
(f"{int(self.a * 255):02X}", )))[index]
|
|
522
515
|
|
|
523
516
|
def __repr__(self) -> str:
|
|
524
517
|
return f'hexa(#{self.r:02X}{self.g:02X}{self.b:02X}{"" if self.a is None else f"{int(self.a * 255):02X}"})'
|
|
@@ -539,9 +532,7 @@ class hexa:
|
|
|
539
532
|
def dict(self) -> dict:
|
|
540
533
|
"""Returns the color components as a dictionary with hex string values for keys `'r'`, `'g'`, `'b'` and optionally `'a'`"""
|
|
541
534
|
return (
|
|
542
|
-
dict(r=f"{self.r:02X}", g=f"{self.g:02X}", b=f"{self.b:02X}")
|
|
543
|
-
if self.a is None
|
|
544
|
-
else dict(
|
|
535
|
+
dict(r=f"{self.r:02X}", g=f"{self.g:02X}", b=f"{self.b:02X}") if self.a is None else dict(
|
|
545
536
|
r=f"{self.r:02X}",
|
|
546
537
|
g=f"{self.g:02X}",
|
|
547
538
|
b=f"{self.b:02X}",
|
|
@@ -653,18 +644,14 @@ class Color:
|
|
|
653
644
|
elif isinstance(color, (list, tuple)):
|
|
654
645
|
if allow_alpha and Color.has_alpha(color):
|
|
655
646
|
return (
|
|
656
|
-
0 <= color[0] <= 255
|
|
657
|
-
and 0 <= color[1] <= 255
|
|
658
|
-
and 0 <= color[2] <= 255
|
|
647
|
+
0 <= color[0] <= 255 and 0 <= color[1] <= 255 and 0 <= color[2] <= 255
|
|
659
648
|
and (0 <= color[3] <= 1 or color[3] is None)
|
|
660
649
|
)
|
|
661
650
|
return 0 <= color[0] <= 255 and 0 <= color[1] <= 255 and 0 <= color[2] <= 255
|
|
662
651
|
elif isinstance(color, dict):
|
|
663
652
|
if allow_alpha and Color.has_alpha(color):
|
|
664
653
|
return (
|
|
665
|
-
0 <= color["r"] <= 255
|
|
666
|
-
and 0 <= color["g"] <= 255
|
|
667
|
-
and 0 <= color["b"] <= 255
|
|
654
|
+
0 <= color["r"] <= 255 and 0 <= color["g"] <= 255 and 0 <= color["b"] <= 255
|
|
668
655
|
and (0 <= color["a"] <= 1 or color["a"] is None)
|
|
669
656
|
)
|
|
670
657
|
return 0 <= color["r"] <= 255 and 0 <= color["g"] <= 255 and 0 <= color["b"] <= 255
|
|
@@ -682,9 +669,7 @@ class Color:
|
|
|
682
669
|
elif isinstance(color, (list, tuple)):
|
|
683
670
|
if allow_alpha and Color.has_alpha(color):
|
|
684
671
|
return (
|
|
685
|
-
0 <= color[0] <= 360
|
|
686
|
-
and 0 <= color[1] <= 100
|
|
687
|
-
and 0 <= color[2] <= 100
|
|
672
|
+
0 <= color[0] <= 360 and 0 <= color[1] <= 100 and 0 <= color[2] <= 100
|
|
688
673
|
and (0 <= color[3] <= 1 or color[3] is None)
|
|
689
674
|
)
|
|
690
675
|
else:
|
|
@@ -692,9 +677,7 @@ class Color:
|
|
|
692
677
|
elif isinstance(color, dict):
|
|
693
678
|
if allow_alpha and Color.has_alpha(color):
|
|
694
679
|
return (
|
|
695
|
-
0 <= color["h"] <= 360
|
|
696
|
-
and 0 <= color["s"] <= 100
|
|
697
|
-
and 0 <= color["l"] <= 100
|
|
680
|
+
0 <= color["h"] <= 360 and 0 <= color["s"] <= 100 and 0 <= color["l"] <= 100
|
|
698
681
|
and (0 <= color["a"] <= 1 or color["a"] is None)
|
|
699
682
|
)
|
|
700
683
|
else:
|
|
@@ -713,24 +696,17 @@ class Color:
|
|
|
713
696
|
is_valid = 0 <= color <= (0xFFFFFFFF if allow_alpha else 0xFFFFFF)
|
|
714
697
|
return (is_valid, "0x") if get_prefix else is_valid
|
|
715
698
|
elif isinstance(color, str):
|
|
716
|
-
color, prefix = (
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
)
|
|
721
|
-
return (
|
|
722
|
-
(bool(_re.fullmatch(Regex.hexa_str(allow_alpha=allow_alpha), color)), prefix)
|
|
723
|
-
if get_prefix
|
|
724
|
-
else bool(_re.fullmatch(Regex.hexa_str(allow_alpha=allow_alpha), color))
|
|
725
|
-
)
|
|
699
|
+
color, prefix = ((color[1:], "#") if color.startswith("#") else
|
|
700
|
+
(color[2:], "0x") if color.startswith("0x") else (color, None))
|
|
701
|
+
return ((bool(_re.fullmatch(Regex.hexa_str(allow_alpha=allow_alpha), color)),
|
|
702
|
+
prefix) if get_prefix else bool(_re.fullmatch(Regex.hexa_str(allow_alpha=allow_alpha), color)))
|
|
726
703
|
except Exception:
|
|
727
704
|
return (False, None) if get_prefix else False
|
|
728
705
|
|
|
729
706
|
@staticmethod
|
|
730
707
|
def is_valid(color: str | list | tuple | dict, allow_alpha: bool = True) -> bool:
|
|
731
708
|
return (
|
|
732
|
-
Color.is_valid_rgba(color, allow_alpha)
|
|
733
|
-
or Color.is_valid_hsla(color, allow_alpha)
|
|
709
|
+
Color.is_valid_rgba(color, allow_alpha) or Color.is_valid_hsla(color, allow_alpha)
|
|
734
710
|
or Color.is_valid_hexa(color, allow_alpha)
|
|
735
711
|
)
|
|
736
712
|
|
|
@@ -796,7 +772,7 @@ class Color:
|
|
|
796
772
|
raise ValueError(f"Invalid color format '{color}'")
|
|
797
773
|
|
|
798
774
|
@staticmethod
|
|
799
|
-
def str_to_rgba(string: str, only_first: bool = False) -> rgba | list[rgba]
|
|
775
|
+
def str_to_rgba(string: str, only_first: bool = False) -> Optional[rgba | list[rgba]]:
|
|
800
776
|
"""Will try to recognize RGBA colors inside a string and output the found ones as RGBA objects.\n
|
|
801
777
|
--------------------------------------------------------------------------------------------------
|
|
802
778
|
If `only_first` is `True` only the first found color will be returned (not as a list)."""
|
|
@@ -823,8 +799,7 @@ class Color:
|
|
|
823
799
|
int(m[2]),
|
|
824
800
|
((int(m[3]) if "." not in m[3] else float(m[3])) if m[3] else None),
|
|
825
801
|
_validate=False,
|
|
826
|
-
)
|
|
827
|
-
for m in matches
|
|
802
|
+
) for m in matches
|
|
828
803
|
]
|
|
829
804
|
|
|
830
805
|
@staticmethod
|
|
@@ -901,15 +876,15 @@ class Color:
|
|
|
901
876
|
if r < 0.03928:
|
|
902
877
|
r = r / 12.92
|
|
903
878
|
else:
|
|
904
|
-
r = ((r + 0.055) / 1.055)
|
|
879
|
+
r = ((r + 0.055) / 1.055)**2.4
|
|
905
880
|
if g < 0.03928:
|
|
906
881
|
g = g / 12.92
|
|
907
882
|
else:
|
|
908
|
-
g = ((g + 0.055) / 1.055)
|
|
883
|
+
g = ((g + 0.055) / 1.055)**2.4
|
|
909
884
|
if b < 0.03928:
|
|
910
885
|
b = b / 12.92
|
|
911
886
|
else:
|
|
912
|
-
b = ((b + 0.055) / 1.055)
|
|
887
|
+
b = ((b + 0.055) / 1.055)**2.4
|
|
913
888
|
l = 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
914
889
|
return round(l * 100) if isinstance(output_type, int) else round(l * 255) if output_type is None else l
|
|
915
890
|
|
|
@@ -918,11 +893,8 @@ class Color:
|
|
|
918
893
|
was_hexa, was_int = Color.is_valid_hexa(text_bg_color), isinstance(text_bg_color, int)
|
|
919
894
|
text_bg_color = Color.to_rgba(text_bg_color)
|
|
920
895
|
brightness = 0.2126 * text_bg_color[0] + 0.7152 * text_bg_color[1] + 0.0722 * text_bg_color[2]
|
|
921
|
-
return (
|
|
922
|
-
|
|
923
|
-
if brightness < 128
|
|
924
|
-
else ((0x000 if was_int else hexa("", 0, 0, 0)) if was_hexa else rgba(0, 0, 0, _validate=False))
|
|
925
|
-
)
|
|
896
|
+
return ((hexa("", 255, 255, 255) if was_hexa else rgba(255, 255, 255, _validate=False)) if brightness < 128 else
|
|
897
|
+
((0x000 if was_int else hexa("", 0, 0, 0)) if was_hexa else rgba(0, 0, 0, _validate=False)))
|
|
926
898
|
|
|
927
899
|
@staticmethod
|
|
928
900
|
def adjust_lightness(color: rgba | hexa, lightness_change: float) -> rgba | hexa:
|