xulbux 1.6.9__py3-none-any.whl → 1.7.0__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/xx_color.py CHANGED
@@ -33,10 +33,36 @@ 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
+ from typing import Annotated, TypeAlias, Iterator, Optional, Literal, Union
37
37
  import re as _re
38
38
 
39
39
 
40
+ Int_0_100 = Annotated[int, "An integer value between 0 and 100, inclusive."]
41
+ Int_0_255 = Annotated[int, "An integer value between 0 and 255, inclusive."]
42
+ Int_0_360 = Annotated[int, "An integer value between 0 and 360, inclusive."]
43
+ Float_0_1 = Annotated[float, "A float value between 0.0 and 1.0, inclusive."]
44
+
45
+ Rgba: TypeAlias = Union[
46
+ tuple[Int_0_255, Int_0_255, Int_0_255],
47
+ tuple[Int_0_255, Int_0_255, Int_0_255, Float_0_1],
48
+ list[Int_0_255],
49
+ list[Union[Int_0_255, Float_0_1]],
50
+ dict[str, Union[int, float]],
51
+ "rgba",
52
+ str,
53
+ ]
54
+ Hsla: TypeAlias = Union[
55
+ tuple[Int_0_360, Int_0_100, Int_0_100],
56
+ tuple[Int_0_360, Int_0_100, Int_0_100, Float_0_1],
57
+ list[Union[Int_0_360, Int_0_100]],
58
+ list[Union[Int_0_360, Int_0_100, Float_0_1]],
59
+ dict[str, Union[int, float]],
60
+ "hsla",
61
+ str,
62
+ ]
63
+ Hexa: TypeAlias = Union[str, int, "hexa"]
64
+
65
+
40
66
  class rgba:
41
67
  """An RGB/RGBA color: is a tuple of 3 integers, representing the red (`0`-`255`), green (`0`-`255`), and blue (`0`-`255`).\n
42
68
  Also includes an optional 4th param, which is a float, that represents the alpha channel (`0.0`-`1.0`).\n
@@ -60,7 +86,11 @@ class rgba:
60
86
  - `with_alpha(alpha)` to create a new color with different alpha
61
87
  - `complementary()` to get the complementary color"""
62
88
 
63
- def __init__(self, r: int, g: int, b: int, a: float = None, _validate: bool = True):
89
+ def __init__(self, r: int, g: int, b: int, a: Optional[float] = None, _validate: bool = True):
90
+ self.r: int
91
+ self.g: int
92
+ self.b: int
93
+ self.a: Optional[float]
64
94
  if not _validate:
65
95
  self.r, self.g, self.b, self.a = r, g, b, a
66
96
  return
@@ -79,13 +109,10 @@ class rgba:
79
109
  def __len__(self) -> int:
80
110
  return 3 if self.a is None else 4
81
111
 
82
- def __iter__(self) -> iter:
112
+ def __iter__(self) -> Iterator:
83
113
  return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))
84
114
 
85
- def __dict__(self) -> dict:
86
- return self.dict()
87
-
88
- def __getitem__(self, index: int) -> int:
115
+ def __getitem__(self, index: int) -> int | float:
89
116
  return ((self.r, self.g, self.b) + (() if self.a is None else (self.a, )))[index]
90
117
 
91
118
  def __repr__(self) -> str:
@@ -94,7 +121,7 @@ class rgba:
94
121
  def __str__(self) -> str:
95
122
  return f'({self.r}, {self.g}, {self.b}{"" if self.a is None else f", {self.a}"})'
96
123
 
97
- def __eq__(self, other: "rgba") -> bool:
124
+ def __eq__(self, other: "rgba") -> bool: # type: ignore[override]
98
125
  if not isinstance(other, rgba):
99
126
  return False
100
127
  return (self.r, self.g, self.b, self.a) == (other.r, other.g, other.b, other.a)
@@ -109,7 +136,7 @@ class rgba:
109
136
 
110
137
  def to_hsla(self) -> "hsla":
111
138
  """Returns the color as a `hsla()` color"""
112
- return hsla(*self._rgb_to_hsl(self.r, self.g, self.b), self.a, _validate=False)
139
+ return hsla(*self._rgb_to_hsl(self.r, self.g, self.b), self.a, _validate=False) # type: ignore[positional-arguments]
113
140
 
114
141
  def to_hexa(self) -> "hexa":
115
142
  """Returns the color as a `hexa()` color"""
@@ -147,7 +174,7 @@ class rgba:
147
174
  def invert(self, invert_alpha: bool = False) -> "rgba":
148
175
  """Inverts the color by rotating hue by 180 degrees and inverting lightness"""
149
176
  self.r, self.g, self.b = 255 - self.r, 255 - self.g, 255 - self.b
150
- if invert_alpha:
177
+ if invert_alpha and self.a is not None:
151
178
  self.a = 1 - self.a
152
179
  return rgba(self.r, self.g, self.b, self.a, _validate=False)
153
180
 
@@ -159,10 +186,10 @@ class rgba:
159
186
  - `"wcag3"` Draft WCAG 3.0 standard with improved coefficients
160
187
  - `"simple"` Simple arithmetic mean (less accurate)
161
188
  - `"bt601"` ITU-R BT.601 standard (older TV standard)"""
162
- self.r = self.g = self.b = Color.luminance(self.r, self.g, self.b, method=method)
189
+ self.r = self.g = self.b = int(Color.luminance(self.r, self.g, self.b, method=method))
163
190
  return rgba(self.r, self.g, self.b, self.a, _validate=False)
164
191
 
165
- def blend(self, other: "rgba", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
192
+ def blend(self, other: Rgba, ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
166
193
  """Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
167
194
  - if `ratio` is `0.0` it means 100% of the current color and 0% of the `other` color (2:0 mixture)
168
195
  - if `ratio` is `0.5` it means 50% of both colors (1:1 mixture)
@@ -171,7 +198,7 @@ class rgba:
171
198
  raise ValueError("'ratio' must be a float/int in [0.0, 1.0]")
172
199
  elif not isinstance(other, rgba):
173
200
  if Color.is_valid_rgba(other):
174
- other = rgba(*other, _validate=False)
201
+ other = Color.to_rgba(other)
175
202
  else:
176
203
  raise TypeError("'other' must be a valid RGBA color")
177
204
  ratio *= 2
@@ -217,20 +244,20 @@ class rgba:
217
244
  return self.to_hsla().complementary().to_rgba()
218
245
 
219
246
  def _rgb_to_hsl(self, r: int, g: int, b: int) -> tuple:
220
- r, g, b = r / 255.0, g / 255.0, b / 255.0
221
- max_c, min_c = max(r, g, b), min(r, g, b)
247
+ _r, _g, _b = r / 255.0, g / 255.0, b / 255.0
248
+ max_c, min_c = max(_r, _g, _b), min(_r, _g, _b)
222
249
  l = (max_c + min_c) / 2
223
250
  if max_c == min_c:
224
251
  h = s = 0
225
252
  else:
226
253
  delta = max_c - min_c
227
254
  s = delta / (1 - abs(2 * l - 1))
228
- if max_c == r:
229
- h = ((g - b) / delta) % 6
230
- elif max_c == g:
231
- h = ((b - r) / delta) + 2
255
+ if max_c == _r:
256
+ h = ((_g - _b) / delta) % 6
257
+ elif max_c == _g:
258
+ h = ((_b - _r) / delta) + 2
232
259
  else:
233
- h = ((r - g) / delta) + 4
260
+ h = ((_r - _g) / delta) + 4
234
261
  h /= 6
235
262
  return int(round(h * 360)), int(round(s * 100)), int(round(l * 100))
236
263
 
@@ -258,7 +285,11 @@ class hsla:
258
285
  - `with_alpha(alpha)` to create a new color with different alpha
259
286
  - `complementary()` to get the complementary color"""
260
287
 
261
- def __init__(self, h: int, s: int, l: int, a: float = None, _validate: bool = True):
288
+ def __init__(self, h: int, s: int, l: int, a: Optional[float] = None, _validate: bool = True):
289
+ self.h: int
290
+ self.s: int
291
+ self.l: int
292
+ self.a: Optional[float]
262
293
  if not _validate:
263
294
  self.h, self.s, self.l, self.a = h, s, l, a
264
295
  return
@@ -277,13 +308,10 @@ class hsla:
277
308
  def __len__(self) -> int:
278
309
  return 3 if self.a is None else 4
279
310
 
280
- def __iter__(self) -> iter:
311
+ def __iter__(self) -> Iterator:
281
312
  return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))
282
313
 
283
- def __dict__(self) -> dict:
284
- return self.dict()
285
-
286
- def __getitem__(self, index: int) -> int:
314
+ def __getitem__(self, index: int) -> int | float:
287
315
  return ((self.h, self.s, self.l) + (() if self.a is None else (self.a, )))[index]
288
316
 
289
317
  def __repr__(self) -> str:
@@ -292,7 +320,7 @@ class hsla:
292
320
  def __str__(self) -> str:
293
321
  return f'({self.h}°, {self.s}%, {self.l}%{"" if self.a is None else f", {self.a}"})'
294
322
 
295
- def __eq__(self, other: "hsla") -> bool:
323
+ def __eq__(self, other: "hsla") -> bool: # type: ignore[override]
296
324
  if not isinstance(other, hsla):
297
325
  return False
298
326
  return (self.h, self.s, self.l, self.a) == (other.h, other.s, other.l, other.a)
@@ -307,7 +335,7 @@ class hsla:
307
335
 
308
336
  def to_rgba(self) -> "rgba":
309
337
  """Returns the color as a `rgba()` color"""
310
- return rgba(*self._hsl_to_rgb(self.h, self.s, self.l), self.a, _validate=False)
338
+ return rgba(*self._hsl_to_rgb(self.h, self.s, self.l), self.a, _validate=False) # type: ignore[positional-arguments]
311
339
 
312
340
  def to_hexa(self) -> "hexa":
313
341
  """Returns the color as a `hexa()` color"""
@@ -355,7 +383,7 @@ class hsla:
355
383
  """Inverts the color by rotating hue by 180 degrees and inverting lightness"""
356
384
  self.h = (self.h + 180) % 360
357
385
  self.l = 100 - self.l
358
- if invert_alpha:
386
+ if invert_alpha and self.a is not None:
359
387
  self.a = 1 - self.a
360
388
  return hsla(self.h, self.s, self.l, self.a, _validate=False)
361
389
 
@@ -367,11 +395,11 @@ class hsla:
367
395
  - `"wcag3"` Draft WCAG 3.0 standard with improved coefficients
368
396
  - `"simple"` Simple arithmetic mean (less accurate)
369
397
  - `"bt601"` ITU-R BT.601 standard (older TV standard)"""
370
- l = Color.luminance(*self._hsl_to_rgb(self.h, self.s, self.l), method=method)
398
+ l = int(Color.luminance(*self._hsl_to_rgb(self.h, self.s, self.l), method=method))
371
399
  self.h, self.s, self.l, _ = rgba(l, l, l, _validate=False).to_hsla().values()
372
400
  return hsla(self.h, self.s, self.l, self.a, _validate=False)
373
401
 
374
- def blend(self, other: "hsla", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
402
+ def blend(self, other: Hsla, ratio: float = 0.5, additive_alpha: bool = False) -> "hsla":
375
403
  """Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
376
404
  - if `ratio` is `0.0` it means 100% of the current color and 0% of the `other` color (2:0 mixture)
377
405
  - if `ratio` is `0.5` it means 50% of both colors (1:1 mixture)
@@ -406,9 +434,9 @@ class hsla:
406
434
  return hsla((self.h + 180) % 360, self.s, self.l, self.a, _validate=False)
407
435
 
408
436
  def _hsl_to_rgb(self, h: int, s: int, l: int) -> tuple:
409
- h, s, l = h / 360, s / 100, l / 100
410
- if s == 0:
411
- r = g = b = int(l * 255)
437
+ _h, _s, _l = h / 360, s / 100, l / 100
438
+ if _s == 0:
439
+ r = g = b = int(_l * 255)
412
440
  else:
413
441
 
414
442
  def hue_to_rgb(p, q, t):
@@ -424,11 +452,11 @@ class hsla:
424
452
  return p + (q - p) * (2 / 3 - t) * 6
425
453
  return p
426
454
 
427
- q = l * (1 + s) if l < 0.5 else l + s - l * s
428
- p = 2 * l - q
429
- r = int(round(hue_to_rgb(p, q, h + 1 / 3) * 255))
430
- g = int(round(hue_to_rgb(p, q, h) * 255))
431
- b = int(round(hue_to_rgb(p, q, h - 1 / 3) * 255))
455
+ q = _l * (1 + _s) if _l < 0.5 else _l + _s - _l * _s
456
+ p = 2 * _l - q
457
+ r = int(round(hue_to_rgb(p, q, _h + 1 / 3) * 255))
458
+ g = int(round(hue_to_rgb(p, q, _h) * 255))
459
+ b = int(round(hue_to_rgb(p, q, _h - 1 / 3) * 255))
432
460
  return r, g, b
433
461
 
434
462
 
@@ -455,9 +483,20 @@ class hexa:
455
483
  - `with_alpha(alpha)` to create a new color with different alpha
456
484
  - `complementary()` to get the complementary color"""
457
485
 
458
- def __init__(self, color: str | int, _r: int = None, _g: int = None, _b: int = None, _a: float = None):
486
+ def __init__(
487
+ self,
488
+ color: str | int,
489
+ _r: Optional[int] = None,
490
+ _g: Optional[int] = None,
491
+ _b: Optional[int] = None,
492
+ _a: Optional[float] = None,
493
+ ):
494
+ self.r: int
495
+ self.g: int
496
+ self.b: int
497
+ self.a: Optional[float]
459
498
  if all(x is not None for x in (_r, _g, _b)):
460
- self.r, self.g, self.b, self.a = _r, _g, _b, _a
499
+ self.r, self.g, self.b, self.a = _r, _g, _b, _a # type: ignore[assignment]
461
500
  return
462
501
  if isinstance(color, hexa):
463
502
  raise ValueError("Color is already a hexa() color")
@@ -504,14 +543,11 @@ class hexa:
504
543
  def __len__(self) -> int:
505
544
  return 3 if self.a is None else 4
506
545
 
507
- def __iter__(self) -> iter:
546
+ def __iter__(self) -> Iterator:
508
547
  return iter((f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}")
509
548
  + (() if self.a is None else (f"{int(self.a * 255):02X}", )))
510
549
 
511
- def __dict__(self) -> dict:
512
- return self.dict()
513
-
514
- def __getitem__(self, index: int) -> int:
550
+ def __getitem__(self, index: int) -> str | int:
515
551
  return ((f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else
516
552
  (f"{int(self.a * 255):02X}", )))[index]
517
553
 
@@ -521,7 +557,7 @@ class hexa:
521
557
  def __str__(self) -> str:
522
558
  return f'#{self.r:02X}{self.g:02X}{self.b:02X}{"" if self.a is None else f"{int(self.a * 255):02X}"}'
523
559
 
524
- def __eq__(self, other: "hexa") -> bool:
560
+ def __eq__(self, other: "hexa") -> bool: # type: ignore[override]
525
561
  """Returns whether the other color is equal to this one."""
526
562
  if not isinstance(other, hexa):
527
563
  return False
@@ -588,7 +624,7 @@ class hexa:
588
624
  def invert(self, invert_alpha: bool = False) -> "hexa":
589
625
  """Inverts the color by rotating hue by 180 degrees and inverting lightness"""
590
626
  self.r, self.g, self.b, self.a = self.to_rgba(False).invert().values()
591
- if invert_alpha:
627
+ if invert_alpha and self.a is not None:
592
628
  self.a = 1 - self.a
593
629
  return hexa("", self.r, self.g, self.b, self.a)
594
630
 
@@ -600,10 +636,10 @@ class hexa:
600
636
  - `"wcag3"` Draft WCAG 3.0 standard with improved coefficients
601
637
  - `"simple"` Simple arithmetic mean (less accurate)
602
638
  - `"bt601"` ITU-R BT.601 standard (older TV standard)"""
603
- self.r = self.g = self.b = Color.luminance(self.r, self.g, self.b, method=method)
639
+ self.r = self.g = self.b = int(Color.luminance(self.r, self.g, self.b, method=method))
604
640
  return hexa("", self.r, self.g, self.b, self.a)
605
641
 
606
- def blend(self, other: "hexa", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
642
+ def blend(self, other: Hexa, ratio: float = 0.5, additive_alpha: bool = False) -> "hexa":
607
643
  """Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
608
644
  - if `ratio` is `0.0` it means 100% of the current color and 0% of the `other` color (2:0 mixture)
609
645
  - if `ratio` is `0.5` it means 50% of both colors (1:1 mixture)
@@ -641,7 +677,7 @@ class hexa:
641
677
  class Color:
642
678
 
643
679
  @staticmethod
644
- def is_valid_rgba(color: str | list | tuple | dict, allow_alpha: bool = True) -> bool:
680
+ def is_valid_rgba(color: Rgba, allow_alpha: bool = True) -> bool:
645
681
  try:
646
682
  if isinstance(color, rgba):
647
683
  return True
@@ -649,7 +685,7 @@ class Color:
649
685
  if allow_alpha and Color.has_alpha(color):
650
686
  return (
651
687
  0 <= color[0] <= 255 and 0 <= color[1] <= 255 and 0 <= color[2] <= 255
652
- and (0 <= color[3] <= 1 or color[3] is None)
688
+ and (0 <= color[3] <= 1 or color[3] is None) # type: ignore[index]
653
689
  )
654
690
  elif len(color) == 3:
655
691
  return 0 <= color[0] <= 255 and 0 <= color[1] <= 255 and 0 <= color[2] <= 255
@@ -672,7 +708,7 @@ class Color:
672
708
  return False
673
709
 
674
710
  @staticmethod
675
- def is_valid_hsla(color: str | list | tuple | dict, allow_alpha: bool = True) -> bool:
711
+ def is_valid_hsla(color: Hsla, allow_alpha: bool = True) -> bool:
676
712
  try:
677
713
  if isinstance(color, hsla):
678
714
  return True
@@ -680,7 +716,7 @@ class Color:
680
716
  if allow_alpha and Color.has_alpha(color):
681
717
  return (
682
718
  0 <= color[0] <= 360 and 0 <= color[1] <= 100 and 0 <= color[2] <= 100
683
- and (0 <= color[3] <= 1 or color[3] is None)
719
+ and (0 <= color[3] <= 1 or color[3] is None) # type: ignore[index]
684
720
  )
685
721
  elif len(color) == 3:
686
722
  return 0 <= color[0] <= 360 and 0 <= color[1] <= 100 and 0 <= color[2] <= 100
@@ -702,7 +738,11 @@ class Color:
702
738
  return False
703
739
 
704
740
  @staticmethod
705
- def is_valid_hexa(color: str | int, allow_alpha: bool = True, get_prefix: bool = False) -> bool | tuple[bool, str]:
741
+ def is_valid_hexa(
742
+ color: Hexa,
743
+ allow_alpha: bool = True,
744
+ get_prefix: bool = False,
745
+ ) -> bool | tuple[bool, Optional[Literal['#', '0x']]]:
706
746
  try:
707
747
  if isinstance(color, hexa):
708
748
  return (True, "#") if get_prefix else True
@@ -718,21 +758,21 @@ class Color:
718
758
  return (False, None) if get_prefix else False
719
759
 
720
760
  @staticmethod
721
- def is_valid(color: str | list | tuple | dict, allow_alpha: bool = True) -> bool:
761
+ def is_valid(color: Rgba | Hsla | Hexa, allow_alpha: bool = True) -> bool:
722
762
  return bool(
723
- Color.is_valid_rgba(color, allow_alpha) or Color.is_valid_hsla(color, allow_alpha)
724
- or Color.is_valid_hexa(color, allow_alpha)
763
+ Color.is_valid_rgba(color, allow_alpha) or Color.is_valid_hsla(color, allow_alpha) # type: ignore[assignment]
764
+ or Color.is_valid_hexa(color, allow_alpha) # type: ignore[assignment]
725
765
  )
726
766
 
727
767
  @staticmethod
728
- def has_alpha(color: rgba | hsla | hexa) -> bool:
768
+ def has_alpha(color: Rgba | Hsla | Hexa) -> bool:
729
769
  """Check if the given color has an alpha channel.\n
730
770
  ---------------------------------------------------------------------------
731
771
  Input a RGBA, HSLA or HEXA color as `color`.
732
772
  Returns `True` if the color has an alpha channel and `False` otherwise."""
733
773
  if isinstance(color, (rgba, hsla, hexa)):
734
774
  return color.has_alpha()
735
- if Color.is_valid_hexa(color):
775
+ if Color.is_valid_hexa(color): # type: ignore[assignment]
736
776
  if isinstance(color, str):
737
777
  if color.startswith("#"):
738
778
  color = color[1:]
@@ -747,42 +787,42 @@ class Color:
747
787
  return False
748
788
 
749
789
  @staticmethod
750
- def to_rgba(color: hsla | hexa) -> rgba:
790
+ def to_rgba(color: Rgba | Hsla | Hexa) -> rgba:
751
791
  """Will try to convert any color type to a color of type RGBA."""
752
792
  if isinstance(color, (hsla, hexa)):
753
793
  return color.to_rgba()
754
- elif Color.is_valid_hsla(color):
755
- return hsla(*color, _validate=False).to_rgba()
756
- elif Color.is_valid_hexa(color):
757
- return hexa(color).to_rgba()
758
- elif Color.is_valid_rgba(color):
759
- return color if isinstance(color, rgba) else (rgba(*color, _validate=False))
794
+ elif Color.is_valid_hsla(color): # type: ignore[assignment]
795
+ return hsla(*color, _validate=False).to_rgba() # type: ignore[not-iterable]
796
+ elif Color.is_valid_hexa(color): # type: ignore[assignment]
797
+ return hexa(color).to_rgba() # type: ignore[assignment]
798
+ elif Color.is_valid_rgba(color): # type: ignore[assignment]
799
+ return color if isinstance(color, rgba) else (rgba(*color, _validate=False)) # type: ignore[not-iterable]
760
800
  raise ValueError(f"Invalid color format '{color}'")
761
801
 
762
802
  @staticmethod
763
- def to_hsla(color: rgba | hexa) -> hsla:
803
+ def to_hsla(color: Rgba | Hsla | Hexa) -> hsla:
764
804
  """Will try to convert any color type to a color of type HSLA."""
765
805
  if isinstance(color, (rgba, hexa)):
766
806
  return color.to_hsla()
767
- elif Color.is_valid_rgba(color):
768
- return rgba(*color, _validate=False).to_hsla()
769
- elif Color.is_valid_hexa(color):
770
- return hexa(color).to_hsla()
771
- elif Color.is_valid_hsla(color):
772
- return color if isinstance(color, hsla) else (hsla(*color, _validate=False))
807
+ elif Color.is_valid_rgba(color): # type: ignore[assignment]
808
+ return rgba(*color, _validate=False).to_hsla() # type: ignore[not-iterable]
809
+ elif Color.is_valid_hexa(color): # type: ignore[assignment]
810
+ return hexa(color).to_hsla() # type: ignore[assignment]
811
+ elif Color.is_valid_hsla(color): # type: ignore[assignment]
812
+ return color if isinstance(color, hsla) else (hsla(*color, _validate=False)) # type: ignore[not-iterable]
773
813
  raise ValueError(f"Invalid color format '{color}'")
774
814
 
775
815
  @staticmethod
776
- def to_hexa(color: rgba | hsla) -> hexa:
816
+ def to_hexa(color: Rgba | Hsla | Hexa) -> hexa:
777
817
  """Will try to convert any color type to a color of type HEXA."""
778
818
  if isinstance(color, (rgba, hsla)):
779
819
  return color.to_hexa()
780
- elif Color.is_valid_rgba(color):
781
- return rgba(*color, _validate=False).to_hexa()
782
- elif Color.is_valid_hsla(color):
783
- return hsla(*color, _validate=False).to_hexa()
784
- elif Color.is_valid_hexa(color):
785
- return color if isinstance(color, hexa) else hexa(color)
820
+ elif Color.is_valid_rgba(color): # type: ignore[assignment]
821
+ return rgba(*color, _validate=False).to_hexa() # type: ignore[not-iterable]
822
+ elif Color.is_valid_hsla(color): # type: ignore[assignment]
823
+ return hsla(*color, _validate=False).to_hexa() # type: ignore[not-iterable]
824
+ elif Color.is_valid_hexa(color): # type: ignore[assignment]
825
+ return color if isinstance(color, hexa) else hexa(color) # type: ignore[assignment]
786
826
  raise ValueError(f"Invalid color format '{color}'")
787
827
 
788
828
  @staticmethod
@@ -821,7 +861,7 @@ class Color:
821
861
  r: int,
822
862
  g: int,
823
863
  b: int,
824
- a: float = None,
864
+ a: Optional[float] = None,
825
865
  preserve_original: bool = False,
826
866
  ) -> int:
827
867
  """Convert RGBA channels to a HEXA integer (alpha is optional).\n
@@ -879,7 +919,7 @@ class Color:
879
919
  raise ValueError(f"Invalid HEX integer '0x{hex_str}': expected in range [0x000000, 0xFFFFFF]")
880
920
 
881
921
  @staticmethod
882
- def luminance(r: int, g: int, b: int, output_type: type = None, method: str = "wcag2") -> int | float:
922
+ def luminance(r: int, g: int, b: int, output_type: Optional[type] = None, method: str = "wcag2") -> int | float:
883
923
  """Calculates the relative luminance of a color according to various standards.\n
884
924
  ----------------------------------------------------------------------------------
885
925
  The `output_type` controls the range of the returned luminance value:
@@ -891,21 +931,21 @@ class Color:
891
931
  - `"wcag3"` Draft WCAG 3.0 standard with improved coefficients
892
932
  - `"simple"` Simple arithmetic mean (less accurate)
893
933
  - `"bt601"` ITU-R BT.601 standard (older TV standard)"""
894
- r, g, b = r / 255.0, g / 255.0, b / 255.0
934
+ _r, _g, _b = r / 255.0, g / 255.0, b / 255.0
895
935
  if method == "simple":
896
- luminance = (r + g + b) / 3
936
+ luminance = (_r + _g + _b) / 3
897
937
  elif method == "bt601":
898
- luminance = 0.299 * r + 0.587 * g + 0.114 * b
938
+ luminance = 0.299 * _r + 0.587 * _g + 0.114 * _b
899
939
  elif method == "wcag3":
900
- r = Color._linearize_srgb(r)
901
- g = Color._linearize_srgb(g)
902
- b = Color._linearize_srgb(b)
903
- luminance = 0.2126729 * r + 0.7151522 * g + 0.0721750 * b
940
+ _r = Color._linearize_srgb(_r)
941
+ _g = Color._linearize_srgb(_g)
942
+ _b = Color._linearize_srgb(_b)
943
+ luminance = 0.2126729 * _r + 0.7151522 * _g + 0.0721750 * _b
904
944
  else:
905
- r = Color._linearize_srgb(r)
906
- g = Color._linearize_srgb(g)
907
- b = Color._linearize_srgb(b)
908
- luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
945
+ _r = Color._linearize_srgb(_r)
946
+ _g = Color._linearize_srgb(_g)
947
+ _b = Color._linearize_srgb(_b)
948
+ luminance = 0.2126 * _r + 0.7152 * _g + 0.0722 * _b
909
949
  if output_type == int:
910
950
  return round(luminance * 100)
911
951
  elif output_type == float:
@@ -922,47 +962,38 @@ class Color:
922
962
  return ((c + 0.055) / 1.055)**2.4
923
963
 
924
964
  @staticmethod
925
- def text_color_for_on_bg(text_bg_color: rgba | hexa) -> rgba | hexa:
926
- was_hexa, was_int = Color.is_valid_hexa(text_bg_color), isinstance(text_bg_color, int)
965
+ def text_color_for_on_bg(text_bg_color: Rgba | Hexa) -> rgba | hexa | int:
966
+ was_hexa, was_int = Color.is_valid_hexa(text_bg_color), isinstance(text_bg_color, int) # type: ignore[assignment]
927
967
  text_bg_color = Color.to_rgba(text_bg_color)
928
968
  brightness = 0.2126 * text_bg_color[0] + 0.7152 * text_bg_color[1] + 0.0722 * text_bg_color[2]
929
- return ((hexa("", 255, 255, 255) if was_hexa else rgba(255, 255, 255, _validate=False)) if brightness < 128 else
969
+ return (((0xFFFFFF if was_int else hexa("", 255, 255, 255)) if was_hexa else rgba(255, 255, 255, _validate=False))
970
+ if brightness < 128 else
930
971
  ((0x000 if was_int else hexa("", 0, 0, 0)) if was_hexa else rgba(0, 0, 0, _validate=False)))
931
972
 
932
973
  @staticmethod
933
- def adjust_lightness(color: rgba | hexa, lightness_change: float) -> rgba | hexa:
974
+ def adjust_lightness(color: Rgba | Hexa, lightness_change: float) -> rgba | hexa:
934
975
  """In- or decrease the lightness of the input color.\n
935
976
  -----------------------------------------------------------------------------------------------------
936
977
  - color (rgba|hexa): HEX or RGBA color
937
978
  - lightness_change (float): float between -1.0 (darken by `100%`) and 1.0 (lighten by `100%`)\n
938
979
  -----------------------------------------------------------------------------------------------------
939
980
  returns (rgba|hexa): the adjusted color in the format of the input color"""
940
- was_hexa = Color.is_valid_hexa(color)
941
- color = Color.to_hsla(color)
942
- h, s, l, a = (
943
- color[0],
944
- color[1],
945
- color[2],
946
- color[3] if Color.has_alpha(color) else None,
947
- )
981
+ was_hexa = Color.is_valid_hexa(color) # type: ignore[assignment]
982
+ _color: hsla = Color.to_hsla(color) # type: ignore[assignment]
983
+ h, s, l, a = (int(_color[0]), int(_color[1]), int(_color[2]), _color[3] if Color.has_alpha(_color) else None)
948
984
  l = int(max(0, min(100, l + lightness_change * 100)))
949
985
  return hsla(h, s, l, a, _validate=False).to_hexa() if was_hexa else hsla(h, s, l, a, _validate=False).to_rgba()
950
986
 
951
987
  @staticmethod
952
- def adjust_saturation(color: rgba | hexa, saturation_change: float) -> rgba | hexa:
988
+ def adjust_saturation(color: Rgba | Hsla | Hexa, saturation_change: float) -> rgba | hexa:
953
989
  """In- or decrease the saturation of the input color.\n
954
990
  -----------------------------------------------------------------------------------------------------------
955
991
  - color (rgba|hexa): HEX or RGBA color
956
992
  - saturation_change (float): float between -1.0 (saturate by `100%`) and 1.0 (desaturate by `100%`)\n
957
993
  -----------------------------------------------------------------------------------------------------------
958
994
  returns (rgba|hexa): the adjusted color in the format of the input color"""
959
- was_hexa = Color.is_valid_hexa(color)
960
- color = Color.to_hsla(color)
961
- h, s, l, a = (
962
- color[0],
963
- color[1],
964
- color[2],
965
- color[3] if Color.has_alpha(color) else None,
966
- )
995
+ was_hexa = Color.is_valid_hexa(color) # type: ignore[assignment]
996
+ _color: hsla = Color.to_hsla(color) # type: ignore[assignment]
997
+ h, s, l, a = (int(_color[0]), int(_color[1]), int(_color[2]), _color[3] if Color.has_alpha(_color) else None)
967
998
  s = int(max(0, min(100, s + saturation_change * 100)))
968
999
  return hsla(h, s, l, a, _validate=False).to_hexa() if was_hexa else hsla(h, s, l, a, _validate=False).to_rgba()