xulbux 1.6.4__py3-none-any.whl → 1.6.6__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.
Potentially problematic release.
This version of xulbux might be problematic. Click here for more details.
- xulbux/__init__.py +2 -2
- xulbux/_cli_.py +9 -9
- xulbux/_consts_.py +71 -58
- xulbux/xx_code.py +37 -42
- xulbux/xx_color.py +49 -79
- xulbux/xx_console.py +197 -109
- xulbux/xx_data.py +177 -126
- xulbux/xx_env_path.py +1 -5
- xulbux/xx_file.py +1 -1
- xulbux/xx_format_codes.py +40 -38
- xulbux/xx_json.py +2 -5
- xulbux/xx_path.py +5 -5
- xulbux/xx_regex.py +18 -20
- xulbux/xx_string.py +28 -82
- xulbux/xx_system.py +5 -13
- {xulbux-1.6.4.dist-info → xulbux-1.6.6.dist-info}/METADATA +19 -17
- xulbux-1.6.6.dist-info/RECORD +21 -0
- xulbux-1.6.4.dist-info/RECORD +0 -21
- {xulbux-1.6.4.dist-info → xulbux-1.6.6.dist-info}/LICENSE +0 -0
- {xulbux-1.6.4.dist-info → xulbux-1.6.6.dist-info}/WHEEL +0 -0
- {xulbux-1.6.4.dist-info → xulbux-1.6.6.dist-info}/entry_points.txt +0 -0
- {xulbux-1.6.4.dist-info → xulbux-1.6.6.dist-info}/top_level.txt +0 -0
xulbux/__init__.py
CHANGED
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
• REGEX PATTERN TEMPLATES xx.Regex
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
__version__ = "1.6.
|
|
22
|
+
__version__ = "1.6.6"
|
|
23
23
|
__author__ = "XulbuX"
|
|
24
24
|
__email__ = "xulbux.real@gmail.com"
|
|
25
25
|
__license__ = "MIT"
|
|
26
26
|
__copyright__ = "Copyright (c) 2024 XulbuX"
|
|
27
|
-
__url__ = "https://github.com/XulbuX
|
|
27
|
+
__url__ = "https://github.com/XulbuX/PythonLibraryXulbuX"
|
|
28
28
|
__description__ = "A library which includes a lot of really helpful functions."
|
|
29
29
|
__all__ = [
|
|
30
30
|
"_consts_",
|
xulbux/_cli_.py
CHANGED
|
@@ -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)
|
xulbux/_consts_.py
CHANGED
|
@@ -1,76 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
30
42
|
class CHARS:
|
|
43
|
+
"""Strings with only certain text characters."""
|
|
31
44
|
|
|
32
45
|
# CODE TO SIGNAL, ALL CHARACTERS ARE ALLOWED
|
|
33
|
-
all =
|
|
46
|
+
all = _AllTextCharacters
|
|
34
47
|
|
|
35
48
|
# DIGIT SETS
|
|
36
|
-
digits = "0123456789"
|
|
37
|
-
float_digits = digits + "."
|
|
38
|
-
hex_digits = digits + "#abcdefABCDEF"
|
|
49
|
+
digits: str = "0123456789"
|
|
50
|
+
float_digits: str = digits + "."
|
|
51
|
+
hex_digits: str = digits + "#abcdefABCDEF"
|
|
39
52
|
|
|
40
53
|
# LETTER CATEGORIES
|
|
41
|
-
lowercase = "abcdefghijklmnopqrstuvwxyz"
|
|
42
|
-
lowercase_extended = lowercase + "äëïöüÿàèìòùáéíóúýâêîôûãñõåæç"
|
|
43
|
-
uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
44
|
-
uppercase_extended = uppercase + "ÄËÏÖÜÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÅÆÇß"
|
|
54
|
+
lowercase: str = "abcdefghijklmnopqrstuvwxyz"
|
|
55
|
+
lowercase_extended: str = lowercase + "äëïöüÿàèìòùáéíóúýâêîôûãñõåæç"
|
|
56
|
+
uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
57
|
+
uppercase_extended: str = uppercase + "ÄËÏÖÜÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÅÆÇß"
|
|
45
58
|
|
|
46
59
|
# COMBINED LETTER SETS
|
|
47
|
-
letters = lowercase + uppercase
|
|
48
|
-
letters_extended = lowercase_extended + uppercase_extended
|
|
60
|
+
letters: str = lowercase + uppercase
|
|
61
|
+
letters_extended: str = lowercase_extended + uppercase_extended
|
|
49
62
|
|
|
50
63
|
# ASCII sets
|
|
51
|
-
special_ascii = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
|
52
|
-
special_ascii_extended = special_ascii + "ø£Ø×ƒªº¿®¬½¼¡«»░▒▓│┤©╣║╗╝¢¥┐└┴┬├─┼╚╔╩╦╠═╬¤ðÐı┘┌█▄¦▀µþÞ¯´≡±‗¾¶§÷¸°¨·¹³²■ "
|
|
53
|
-
standard_ascii = special_ascii + digits + letters
|
|
54
|
-
full_ascii = special_ascii_extended + digits + letters_extended
|
|
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
|
|
55
68
|
|
|
56
69
|
|
|
57
70
|
class ANSI:
|
|
71
|
+
"""Constants and class-methods for use of ANSI escape codes."""
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
escaped_char = "\\x1b"
|
|
73
|
+
escaped_char: str = "\\x1b"
|
|
62
74
|
CHAR = char = "\x1b"
|
|
63
75
|
START = start = "["
|
|
64
76
|
SEP = sep = ";"
|
|
65
77
|
END = end = "m"
|
|
66
|
-
default_color_modifiers = {"lighten": "+l", "darken": "-d"}
|
|
78
|
+
default_color_modifiers: dict[str, str] = {"lighten": "+l", "darken": "-d"}
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
@classmethod
|
|
81
|
+
def seq(cls, parts: int = 1) -> str:
|
|
69
82
|
"""Generate an ANSI sequence with `parts` amount of placeholders."""
|
|
70
|
-
return CHAR + START + SEP.join(["{}" for _ in range(parts)]) + END
|
|
83
|
+
return cls.CHAR + cls.START + cls.SEP.join(["{}" for _ in range(parts)]) + cls.END
|
|
71
84
|
|
|
72
|
-
seq_color:
|
|
73
|
-
seq_bg_color:
|
|
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
|
|
74
87
|
|
|
75
88
|
color_map: list[str] = [
|
|
76
89
|
########### DEFAULT CONSOLE COLOR NAMES ############
|
|
@@ -84,8 +97,8 @@ class ANSI:
|
|
|
84
97
|
"white",
|
|
85
98
|
]
|
|
86
99
|
|
|
87
|
-
codes_map: dict[str | tuple[str], int] = {
|
|
88
|
-
|
|
100
|
+
codes_map: dict[str | tuple[str, ...], int] = {
|
|
101
|
+
################# SPECIFIC RESETS ##################
|
|
89
102
|
"_": 0,
|
|
90
103
|
("_bold", "_b"): 22,
|
|
91
104
|
("_dim", "_d"): 22,
|
|
@@ -97,7 +110,7 @@ class ANSI:
|
|
|
97
110
|
("_strikethrough", "_s"): 29,
|
|
98
111
|
("_color", "_c"): 39,
|
|
99
112
|
("_background", "_bg"): 49,
|
|
100
|
-
################### TEXT
|
|
113
|
+
################### TEXT STYLES ####################
|
|
101
114
|
("bold", "b"): 1,
|
|
102
115
|
("dim", "d"): 2,
|
|
103
116
|
("italic", "i"): 3,
|
|
@@ -106,7 +119,7 @@ class ANSI:
|
|
|
106
119
|
("hidden", "hide", "h"): 8,
|
|
107
120
|
("strikethrough", "s"): 9,
|
|
108
121
|
("double-underline", "du"): 21,
|
|
109
|
-
|
|
122
|
+
################## DEFAULT COLORS ##################
|
|
110
123
|
"black": 30,
|
|
111
124
|
"red": 31,
|
|
112
125
|
"green": 32,
|
|
@@ -115,7 +128,7 @@ class ANSI:
|
|
|
115
128
|
"magenta": 35,
|
|
116
129
|
"cyan": 36,
|
|
117
130
|
"white": 37,
|
|
118
|
-
|
|
131
|
+
############## BRIGHT DEFAULT COLORS ###############
|
|
119
132
|
"br:black": 90,
|
|
120
133
|
"br:red": 91,
|
|
121
134
|
"br:green": 92,
|
|
@@ -124,7 +137,7 @@ class ANSI:
|
|
|
124
137
|
"br:magenta": 95,
|
|
125
138
|
"br:cyan": 96,
|
|
126
139
|
"br:white": 97,
|
|
127
|
-
|
|
140
|
+
############ DEFAULT BACKGROUND COLORS #############
|
|
128
141
|
"bg:black": 40,
|
|
129
142
|
"bg:red": 41,
|
|
130
143
|
"bg:green": 42,
|
|
@@ -133,7 +146,7 @@ class ANSI:
|
|
|
133
146
|
"bg:magenta": 45,
|
|
134
147
|
"bg:cyan": 46,
|
|
135
148
|
"bg:white": 47,
|
|
136
|
-
|
|
149
|
+
######### BRIGHT DEFAULT BACKGROUND COLORS #########
|
|
137
150
|
"bg:br:black": 100,
|
|
138
151
|
"bg:br:red": 101,
|
|
139
152
|
"bg:br:green": 102,
|
xulbux/xx_code.py
CHANGED
|
@@ -59,47 +59,42 @@ class Code:
|
|
|
59
59
|
js_pattern = _rx.compile(
|
|
60
60
|
Regex.outside_strings(
|
|
61
61
|
r"""^(?:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
+
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|(\btypeof\b) # TYPEOF OPERATOR
|
|
100
|
-
|(\bvoid\b) # VOID OPERATOR
|
|
101
|
-
)[\s\S]*$"""
|
|
102
|
-
),
|
|
103
|
-
_rx.VERBOSE | _rx.IGNORECASE,
|
|
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
|
|
104
99
|
)
|
|
105
100
|
return bool(js_pattern.fullmatch(code))
|
xulbux/xx_color.py
CHANGED
|
@@ -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
|
|
|
@@ -75,25 +76,25 @@ class rgba:
|
|
|
75
76
|
self.r, self.g, self.b = r, g, b
|
|
76
77
|
self.a = None if a is None else (1.0 if a > 1.0 else float(a))
|
|
77
78
|
|
|
78
|
-
def __len__(self):
|
|
79
|
+
def __len__(self) -> int:
|
|
79
80
|
return 3 if self.a is None else 4
|
|
80
81
|
|
|
81
|
-
def __iter__(self):
|
|
82
|
-
return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))
|
|
82
|
+
def __iter__(self) -> iter:
|
|
83
|
+
return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))
|
|
83
84
|
|
|
84
|
-
def __dict__(self):
|
|
85
|
+
def __dict__(self) -> dict:
|
|
85
86
|
return self.dict()
|
|
86
87
|
|
|
87
|
-
def __getitem__(self, index):
|
|
88
|
-
return ((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))[index]
|
|
88
|
+
def __getitem__(self, index: int) -> int:
|
|
89
|
+
return ((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))[index]
|
|
89
90
|
|
|
90
|
-
def __repr__(self):
|
|
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}"})'
|
|
92
93
|
|
|
93
|
-
def __str__(self):
|
|
94
|
+
def __str__(self) -> str:
|
|
94
95
|
return f'({self.r}, {self.g}, {self.b}{"" if self.a is None else f", {self.a}"})'
|
|
95
96
|
|
|
96
|
-
def __eq__(self, other):
|
|
97
|
+
def __eq__(self, other: "rgba") -> bool:
|
|
97
98
|
if not isinstance(other, rgba):
|
|
98
99
|
return False
|
|
99
100
|
return (self.r, self.g, self.b, 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)
|
|
@@ -278,25 +273,25 @@ class hsla:
|
|
|
278
273
|
self.h, self.s, self.l = h, s, l
|
|
279
274
|
self.a = None if a is None else (1.0 if a > 1.0 else float(a))
|
|
280
275
|
|
|
281
|
-
def __len__(self):
|
|
276
|
+
def __len__(self) -> int:
|
|
282
277
|
return 3 if self.a is None else 4
|
|
283
278
|
|
|
284
|
-
def __iter__(self):
|
|
285
|
-
return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))
|
|
279
|
+
def __iter__(self) -> iter:
|
|
280
|
+
return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))
|
|
286
281
|
|
|
287
|
-
def __dict__(self):
|
|
282
|
+
def __dict__(self) -> dict:
|
|
288
283
|
return self.dict()
|
|
289
284
|
|
|
290
|
-
def __getitem__(self, index):
|
|
291
|
-
return ((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))[index]
|
|
285
|
+
def __getitem__(self, index: int) -> int:
|
|
286
|
+
return ((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))[index]
|
|
292
287
|
|
|
293
|
-
def __repr__(self):
|
|
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}"})'
|
|
295
290
|
|
|
296
|
-
def __str__(self):
|
|
291
|
+
def __str__(self) -> str:
|
|
297
292
|
return f'({self.h}, {self.s}, {self.l}{"" if self.a is None else f", {self.a}"})'
|
|
298
293
|
|
|
299
|
-
def __eq__(self, other):
|
|
294
|
+
def __eq__(self, other: "hsla") -> bool:
|
|
300
295
|
if not isinstance(other, hsla):
|
|
301
296
|
return False
|
|
302
297
|
return (self.h, self.s, self.l, self.a) == (
|
|
@@ -504,29 +499,27 @@ class hexa:
|
|
|
504
499
|
else:
|
|
505
500
|
raise TypeError(f"HEX color must be of type 'str' or 'int': got '{type(color)}'")
|
|
506
501
|
|
|
507
|
-
def __len__(self):
|
|
502
|
+
def __len__(self) -> int:
|
|
508
503
|
return 3 if self.a is None else 4
|
|
509
504
|
|
|
510
|
-
def __iter__(self):
|
|
511
|
-
return iter(
|
|
512
|
-
|
|
513
|
-
)
|
|
505
|
+
def __iter__(self) -> iter:
|
|
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
|
-
def __dict__(self):
|
|
509
|
+
def __dict__(self) -> dict:
|
|
516
510
|
return self.dict()
|
|
517
511
|
|
|
518
|
-
def __getitem__(self, index):
|
|
519
|
-
return (
|
|
520
|
-
|
|
521
|
-
)[index]
|
|
512
|
+
def __getitem__(self, index: int) -> int:
|
|
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
|
-
def __repr__(self):
|
|
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}"})'
|
|
525
518
|
|
|
526
|
-
def __str__(self):
|
|
519
|
+
def __str__(self) -> str:
|
|
527
520
|
return f'#{self.r:02X}{self.g:02X}{self.b:02X}{"" if self.a is None else f"{int(self.a * 255):02X}"}'
|
|
528
521
|
|
|
529
|
-
def __eq__(self, other):
|
|
522
|
+
def __eq__(self, other: "hexa") -> bool:
|
|
530
523
|
if not isinstance(other, hexa):
|
|
531
524
|
return False
|
|
532
525
|
return (self.r, self.g, self.b, self.a) == (
|
|
@@ -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,30 +876,25 @@ 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
|
|
|
916
891
|
@staticmethod
|
|
917
|
-
def text_color_for_on_bg(
|
|
918
|
-
text_bg_color: rgba | hexa = "#FFF",
|
|
919
|
-
) -> rgba | hexa:
|
|
892
|
+
def text_color_for_on_bg(text_bg_color: rgba | hexa) -> rgba | hexa:
|
|
920
893
|
was_hexa, was_int = Color.is_valid_hexa(text_bg_color), isinstance(text_bg_color, int)
|
|
921
894
|
text_bg_color = Color.to_rgba(text_bg_color)
|
|
922
895
|
brightness = 0.2126 * text_bg_color[0] + 0.7152 * text_bg_color[1] + 0.0722 * text_bg_color[2]
|
|
923
|
-
return (
|
|
924
|
-
|
|
925
|
-
if brightness < 128
|
|
926
|
-
else ((0x000 if was_int else hexa("", 0, 0, 0)) if was_hexa else rgba(0, 0, 0, _validate=False))
|
|
927
|
-
)
|
|
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)))
|
|
928
898
|
|
|
929
899
|
@staticmethod
|
|
930
900
|
def adjust_lightness(color: rgba | hexa, lightness_change: float) -> rgba | hexa:
|