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.

Files changed (35) hide show
  1. {xulbux-1.6.5/src/xulbux.egg-info → xulbux-1.6.6}/PKG-INFO +3 -1
  2. {xulbux-1.6.5 → xulbux-1.6.6}/pyproject.toml +7 -5
  3. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/__init__.py +1 -1
  4. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/_cli_.py +9 -9
  5. xulbux-1.6.6/src/xulbux/_consts_.py +158 -0
  6. xulbux-1.6.6/src/xulbux/xx_code.py +100 -0
  7. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_color.py +27 -55
  8. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_console.py +154 -106
  9. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_data.py +176 -125
  10. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_env_path.py +1 -5
  11. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_format_codes.py +26 -37
  12. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_json.py +2 -5
  13. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_path.py +5 -5
  14. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_regex.py +18 -20
  15. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_string.py +23 -76
  16. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_system.py +5 -13
  17. {xulbux-1.6.5 → xulbux-1.6.6/src/xulbux.egg-info}/PKG-INFO +3 -1
  18. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/requires.txt +2 -0
  19. xulbux-1.6.6/tests/test_console_info.py +37 -0
  20. {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_data.py +2 -2
  21. xulbux-1.6.5/src/xulbux/_consts_.py +0 -145
  22. xulbux-1.6.5/src/xulbux/xx_code.py +0 -105
  23. xulbux-1.6.5/tests/test_console_info.py +0 -19
  24. {xulbux-1.6.5 → xulbux-1.6.6}/LICENSE +0 -0
  25. {xulbux-1.6.5 → xulbux-1.6.6}/README.md +0 -0
  26. {xulbux-1.6.5 → xulbux-1.6.6}/setup.cfg +0 -0
  27. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux/xx_file.py +0 -0
  28. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/SOURCES.txt +0 -0
  29. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/dependency_links.txt +0 -0
  30. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/entry_points.txt +0 -0
  31. {xulbux-1.6.5 → xulbux-1.6.6}/src/xulbux.egg-info/top_level.txt +0 -0
  32. {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_color.py +0 -0
  33. {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_color_types.py +0 -0
  34. {xulbux-1.6.5 → xulbux-1.6.6}/tests/test_env_vars.py +0 -0
  35. {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.5
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.5"
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
- extend-ignore = ["E203", "E266", "E501", "W503", "E303"]
108
- max-complexity = 18
109
- select = ["B", "C", "E", "F", "W", "T4", "B9"]
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"]
@@ -19,7 +19,7 @@
19
19
  • REGEX PATTERN TEMPLATES xx.Regex
20
20
  """
21
21
 
22
- __version__ = "1.6.5"
22
+ __version__ = "1.6.6"
23
23
  __author__ = "XulbuX"
24
24
  __email__ = "xulbux.real@gmail.com"
25
25
  __license__ = "MIT"
@@ -1,5 +1,5 @@
1
1
  from . import __version__
2
- from ._consts_ import DEFAULT
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": DEFAULT.color["ice"],
11
- "import": DEFAULT.color["red"],
12
- "class": DEFAULT.color["lavender"],
13
- "types": DEFAULT.color["lightblue"],
14
- "punctuators": DEFAULT.color["darkgray"],
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:{DEFAULT.color['gray']}|#000] v[b]{__version__} [*]
21
+ [b|#7075FF]/_/|_|\____/\__/\____/\____//_/|_| [*|BG:{COLOR.gray}|#000] v[b]{__version__} [*]
22
22
 
23
- [i|{DEFAULT.color['coral']}]A TON OF COOL FUNCTIONS, YOU NEED![*]
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=DEFAULT.text_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
- (f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else (f"{int(self.a * 255):02X}",))
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
- (f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else (f"{int(self.a * 255):02X}",))
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
- (color[1:], "#")
718
- if color.startswith("#")
719
- else (color[2:], "0x") if color.startswith("0x") else (color, None)
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] | None:
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) ** 2.4
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) ** 2.4
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) ** 2.4
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
- (hexa("", 255, 255, 255) if was_hexa else rgba(255, 255, 255, _validate=False))
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: