chromatic-python 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chromatic/_typing.py +37 -14
- chromatic/_version.py +2 -2
- chromatic/color/colorconv.py +26 -6
- chromatic/color/core.py +95 -33
- chromatic/color/core.pyi +63 -15
- chromatic/color/iterators.py +11 -5
- chromatic/color/palette.py +36 -12
- chromatic/color/palette.pyi +19 -3
- chromatic/data/__init__.py +8 -1
- chromatic/data/__init__.pyi +8 -1
- chromatic/data/userfont.py +9 -3
- chromatic/data/userfont.pyi +3 -1
- chromatic/demo.py +43 -17
- chromatic/image/_array.py +379 -368
- chromatic/image/_glyph_proc.py +2 -10
- {chromatic_python-0.3.0.dist-info → chromatic_python-0.3.1.dist-info}/METADATA +1 -1
- chromatic_python-0.3.1.dist-info/RECORD +35 -0
- chromatic_python-0.3.0.dist-info/RECORD +0 -35
- {chromatic_python-0.3.0.dist-info → chromatic_python-0.3.1.dist-info}/WHEEL +0 -0
- {chromatic_python-0.3.0.dist-info → chromatic_python-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {chromatic_python-0.3.0.dist-info → chromatic_python-0.3.1.dist-info}/top_level.txt +0 -0
chromatic/_typing.py
CHANGED
|
@@ -50,8 +50,12 @@ _T_co = TypeVar('_T_co', covariant=True)
|
|
|
50
50
|
_T_contra = TypeVar('_T_contra', contravariant=True)
|
|
51
51
|
_AnyNumber_co = TypeVar('_AnyNumber_co', number, Number, covariant=True)
|
|
52
52
|
|
|
53
|
-
type ArrayReducerFunc[_SCT: generic] = Callable[
|
|
54
|
-
|
|
53
|
+
type ArrayReducerFunc[_SCT: generic] = Callable[
|
|
54
|
+
Concatenate[_ArrayLike[_SCT], _P], NDArray[_SCT]
|
|
55
|
+
]
|
|
56
|
+
type ShapedNDArray[_Shape: tuple[int, ...], _SCT = generic] = ndarray[
|
|
57
|
+
_Shape, dtype[_SCT]
|
|
58
|
+
]
|
|
55
59
|
type MatrixLike[_SCT: generic] = ShapedNDArray[TupleOf2[int], _SCT]
|
|
56
60
|
type SquareMatrix[_I: int, _SCT: generic] = ShapedNDArray[TupleOf2[_I], _SCT]
|
|
57
61
|
type GlyphArray[_SCT: generic] = SquareMatrix[L[24], _SCT]
|
|
@@ -100,7 +104,11 @@ def type_error_msg(err_obj, *expected, context: str = '', obj_repr=False):
|
|
|
100
104
|
name_slots = ["{%d.__name__!r}" % n for n in range(n_expected)]
|
|
101
105
|
if n_expected > 1:
|
|
102
106
|
name_slots[-1] = f"or {name_slots[-1]}"
|
|
103
|
-
names = (
|
|
107
|
+
names = (
|
|
108
|
+
(', ' if n_expected > 2 else ' ')
|
|
109
|
+
.join([context.strip(), *name_slots])
|
|
110
|
+
.format(*expected)
|
|
111
|
+
)
|
|
104
112
|
if not obj_repr:
|
|
105
113
|
if not isinstance(err_obj, type):
|
|
106
114
|
err_obj = type(err_obj)
|
|
@@ -122,7 +130,10 @@ def is_matching_type(value, typ):
|
|
|
122
130
|
return value in args
|
|
123
131
|
elif isinstance(typ, TypeVar):
|
|
124
132
|
if typ.__constraints__:
|
|
125
|
-
return any(
|
|
133
|
+
return any(
|
|
134
|
+
is_matching_type(value, constraint)
|
|
135
|
+
for constraint in typ.__constraints__
|
|
136
|
+
)
|
|
126
137
|
else:
|
|
127
138
|
return True
|
|
128
139
|
elif origin is type:
|
|
@@ -180,7 +191,9 @@ def is_matching_typed_dict(__d: dict, typed_dict: type[dict]) -> tuple[bool, str
|
|
|
180
191
|
field = __d.get(name)
|
|
181
192
|
if field is None or is_matching_type(field, typ):
|
|
182
193
|
continue
|
|
183
|
-
return False, type_error_msg(
|
|
194
|
+
return False, type_error_msg(
|
|
195
|
+
field, typ, context=f'keyword argument {name!r} of type'
|
|
196
|
+
)
|
|
184
197
|
return True, ''
|
|
185
198
|
|
|
186
199
|
|
|
@@ -231,9 +244,9 @@ class _BoundedDict[_KT, _VT](OrderedDict[_KT, _VT]):
|
|
|
231
244
|
|
|
232
245
|
|
|
233
246
|
_SUBTYPE_CACHE: _BoundedDict[int, ...] = _BoundedDict()
|
|
234
|
-
_ATTR_GETTERS: _BoundedDict[
|
|
235
|
-
|
|
236
|
-
)
|
|
247
|
+
_ATTR_GETTERS: _BoundedDict[
|
|
248
|
+
..., tuple[Callable[[Iterable], NamedTuple], op.attrgetter]
|
|
249
|
+
] = _BoundedDict()
|
|
237
250
|
|
|
238
251
|
|
|
239
252
|
def _unique_attrs(obj) -> Optional['NamedTuple']:
|
|
@@ -278,7 +291,8 @@ def _sort_attrs(obj, tp_name, attr_names):
|
|
|
278
291
|
try:
|
|
279
292
|
sig = inspect.signature(type(obj))
|
|
280
293
|
indices = (
|
|
281
|
-
dict.fromkeys(field_names, inf)
|
|
294
|
+
dict.fromkeys(field_names, inf)
|
|
295
|
+
| {p: i for i, p in enumerate(sig.parameters)}
|
|
282
296
|
).values()
|
|
283
297
|
for names in (attr_names, field_names):
|
|
284
298
|
names.sort(key=dict(zip(names, indices)).__getitem__)
|
|
@@ -300,7 +314,9 @@ def _sort_attrs(obj, tp_name, attr_names):
|
|
|
300
314
|
while sig_start not in line:
|
|
301
315
|
line = next(lines)
|
|
302
316
|
_, _, params = line.partition(sig_start)
|
|
303
|
-
params, _, _ = (
|
|
317
|
+
params, _, _ = (
|
|
318
|
+
s.translate(no_square_parens) for s in params.partition(')')
|
|
319
|
+
)
|
|
304
320
|
maybe_sigs.add(params)
|
|
305
321
|
except StopIteration:
|
|
306
322
|
break
|
|
@@ -308,15 +324,20 @@ def _sort_attrs(obj, tp_name, attr_names):
|
|
|
308
324
|
if maybe_sigs:
|
|
309
325
|
if len(maybe_sigs) > 1:
|
|
310
326
|
sig = max(
|
|
311
|
-
maybe_sigs,
|
|
327
|
+
maybe_sigs,
|
|
328
|
+
key=lambda s: sum(1 for sub in s.split(', ') if sub in field_names),
|
|
312
329
|
)
|
|
313
330
|
else:
|
|
314
331
|
sig = maybe_sigs.pop()
|
|
315
332
|
positions = {x: i for i, x in enumerate(sig.split(', ')) if x}
|
|
316
333
|
sorted_field_names = sorted(field_names, key=lambda k: positions.get(k, inf))
|
|
317
|
-
transitions = {
|
|
334
|
+
transitions = {
|
|
335
|
+
idx: sorted_field_names.index(x) for idx, x in enumerate(field_names)
|
|
336
|
+
}
|
|
318
337
|
field_names = sorted_field_names
|
|
319
|
-
attr_names = [
|
|
338
|
+
attr_names = [
|
|
339
|
+
attr_names[k] for k in map(transitions.__getitem__, range(len(attr_names)))
|
|
340
|
+
]
|
|
320
341
|
for Names in (attr_names, field_names):
|
|
321
342
|
name_attr = next((s for s in Names if s.strip('_') == 'name'), None)
|
|
322
343
|
if name_attr is not None:
|
|
@@ -353,7 +374,9 @@ def subtype[_T](typ: _T) -> _T:
|
|
|
353
374
|
args_list = list(args)
|
|
354
375
|
if (
|
|
355
376
|
literals := [
|
|
356
|
-
idx
|
|
377
|
+
idx
|
|
378
|
+
for idx, elem in enumerate(args)
|
|
379
|
+
if isinstance(elem, _LiteralGenericType)
|
|
357
380
|
]
|
|
358
381
|
) and len(literals) > 1:
|
|
359
382
|
|
chromatic/_version.py
CHANGED
chromatic/color/colorconv.py
CHANGED
|
@@ -29,7 +29,14 @@ from typing import Final, Literal, SupportsInt, TypeGuard
|
|
|
29
29
|
|
|
30
30
|
import numpy as np
|
|
31
31
|
|
|
32
|
-
from .._typing import
|
|
32
|
+
from .._typing import (
|
|
33
|
+
Float3Tuple,
|
|
34
|
+
FloatSequence,
|
|
35
|
+
Int3Tuple,
|
|
36
|
+
RGBPixel,
|
|
37
|
+
RGBVectorLike,
|
|
38
|
+
ShapedNDArray,
|
|
39
|
+
)
|
|
33
40
|
|
|
34
41
|
|
|
35
42
|
@lru_cache
|
|
@@ -107,7 +114,10 @@ def lab2xyz(lab: FloatSequence) -> Float3Tuple:
|
|
|
107
114
|
x, y, z = map(
|
|
108
115
|
mul,
|
|
109
116
|
(95.047, 100.0, 108.883),
|
|
110
|
-
map(
|
|
117
|
+
map(
|
|
118
|
+
lambda i: (lambda j: j if j > 0.008856 else (i - 16 / 116) / 7.787)(i**3),
|
|
119
|
+
(x, y, z),
|
|
120
|
+
),
|
|
111
121
|
)
|
|
112
122
|
return x, y, z
|
|
113
123
|
|
|
@@ -127,7 +137,9 @@ def rgb2xyz(rgb: RGBPixel) -> Float3Tuple:
|
|
|
127
137
|
|
|
128
138
|
|
|
129
139
|
def xyz2rgb(xyz: ShapedNDArray[tuple[Literal[3]], np.float64]) -> Int3Tuple:
|
|
130
|
-
r, g, b = (
|
|
140
|
+
r, g, b = (
|
|
141
|
+
np.clip(M_XYZ2RGB @ np.array(xyz, dtype=np.float64), 0.0, 1.0) * 255.0
|
|
142
|
+
).astype(int)
|
|
131
143
|
return r, g, b
|
|
132
144
|
|
|
133
145
|
|
|
@@ -147,7 +159,13 @@ def hsl2rgb(hsl: FloatSequence) -> Int3Tuple:
|
|
|
147
159
|
mid2 = v - vsf
|
|
148
160
|
r, g, b = (
|
|
149
161
|
round(x * 0xFF)
|
|
150
|
-
for x in [
|
|
162
|
+
for x in [
|
|
163
|
+
[v, mid1, m],
|
|
164
|
+
[mid2, v, m],
|
|
165
|
+
[m, v, mid1],
|
|
166
|
+
[m, mid2, v],
|
|
167
|
+
[mid1, m, v],
|
|
168
|
+
][sextant]
|
|
151
169
|
)
|
|
152
170
|
else:
|
|
153
171
|
r, g, b = [round(L * 0xFF)] * 3
|
|
@@ -273,11 +291,13 @@ def _4b_lookup() -> dict[Int3Tuple, Int3Tuple]:
|
|
|
273
291
|
|
|
274
292
|
rgb_4b_arr = np.asarray(ANSI_4BIT_RGB)
|
|
275
293
|
quants = np.stack(
|
|
276
|
-
np.meshgrid(*np.repeat(np.arange(32).reshape([1, -1]), 3, 0), indexing='ij'),
|
|
294
|
+
np.meshgrid(*np.repeat(np.arange(32).reshape([1, -1]), 3, 0), indexing='ij'),
|
|
295
|
+
axis=-1,
|
|
277
296
|
).reshape([-1, 3])
|
|
278
297
|
nearest_colors = rgb_4b_arr[np.argmin(rgb_dist(quants * 8, rgb_4b_arr), axis=1)]
|
|
279
298
|
table: dict = {
|
|
280
|
-
tuple(map(int, color)): tuple(map(int, nearest_colors[i]))
|
|
299
|
+
tuple(map(int, color)): tuple(map(int, nearest_colors[i]))
|
|
300
|
+
for i, color in enumerate(quants)
|
|
281
301
|
}
|
|
282
302
|
return table
|
|
283
303
|
|
chromatic/color/core.py
CHANGED
|
@@ -149,7 +149,9 @@ _ANSI16C_I2KV = cast(
|
|
|
149
149
|
dict[int, tuple[ColorDictKeys, Int3Tuple]],
|
|
150
150
|
{
|
|
151
151
|
v: (k, ansi_4bit_to_rgb(v))
|
|
152
|
-
for x in (
|
|
152
|
+
for x in (
|
|
153
|
+
zip(('fg', 'bg'), (j, j + 10)) for i in (30, 90) for j in range(i, i + 8)
|
|
154
|
+
)
|
|
153
155
|
for (k, v) in x
|
|
154
156
|
},
|
|
155
157
|
)
|
|
@@ -391,7 +393,9 @@ AnsiColorFormat: TypeAlias = ansicolor4Bit | ansicolor8Bit | ansicolor24Bit
|
|
|
391
393
|
AnsiColorType: TypeAlias = type[AnsiColorFormat]
|
|
392
394
|
AnsiColorParam: TypeAlias = AnsiColorAlias | AnsiColorType
|
|
393
395
|
_AnsiColor_co = TypeVar('_AnsiColor_co', bound=colorbytes, covariant=True)
|
|
394
|
-
_ANSI_COLOR_TYPES = cast(
|
|
396
|
+
_ANSI_COLOR_TYPES = cast(
|
|
397
|
+
frozenset[AnsiColorType], frozenset(colorbytes.__subclasses__())
|
|
398
|
+
)
|
|
395
399
|
_ANSI_FORMAT_MAP = {k: x for x in _ANSI_COLOR_TYPES for k in [x, x.alias]}
|
|
396
400
|
|
|
397
401
|
|
|
@@ -407,7 +411,9 @@ def _is_ansi_type(typ: type):
|
|
|
407
411
|
def sgr_re_pattern():
|
|
408
412
|
uint8_re = r"(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)"
|
|
409
413
|
ansicolor_re = f"[3-4]8;(?:2(?:;{uint8_re}){{3}}|5;{uint8_re})"
|
|
410
|
-
sgr_param_re =
|
|
414
|
+
sgr_param_re = (
|
|
415
|
+
rf"(?:{ansicolor_re}|10[0-7]|9[0-7]|6[0-3]|5[02-5]|2[0-68-9]|[13-4]\d|\d)"
|
|
416
|
+
)
|
|
411
417
|
|
|
412
418
|
return re.compile(rf"\x1b\[(?:{sgr_param_re}(?:;{sgr_param_re})*)?m")
|
|
413
419
|
|
|
@@ -436,7 +442,10 @@ def _split_ansi_escape(__s: str) -> list[tuple['SgrSequence', str]] | None:
|
|
|
436
442
|
out = tmp
|
|
437
443
|
if out and len(out) % 2 != 0:
|
|
438
444
|
out.append({SgrSequence: str, str: SgrSequence}[type(out[-1])]())
|
|
439
|
-
return [
|
|
445
|
+
return [
|
|
446
|
+
(a, b) if isinstance(a, SgrSequence) else (b, a)
|
|
447
|
+
for a, b in zip(out[::2], out[1::2])
|
|
448
|
+
]
|
|
440
449
|
|
|
441
450
|
|
|
442
451
|
def _unwrap_ansi_escape(__b: bytes | bytearray):
|
|
@@ -458,10 +467,12 @@ def get_ansi_type(typ):
|
|
|
458
467
|
from .._typing import unionize
|
|
459
468
|
|
|
460
469
|
repr_getter = lambda t: (t if isinstance(t, type) else type(t))
|
|
461
|
-
msg =
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
470
|
+
msg = (
|
|
471
|
+
"Expected {.__name__!r} or {}, got {.__name__!r} object instead".format(
|
|
472
|
+
str,
|
|
473
|
+
type[unionize(set(map(repr_getter, _ANSI_FORMAT_MAP.values())))],
|
|
474
|
+
repr_getter(typ),
|
|
475
|
+
)
|
|
465
476
|
)
|
|
466
477
|
err = TypeError(msg)
|
|
467
478
|
err.__cause__ = e.__cause__
|
|
@@ -597,10 +608,17 @@ def _get_sgr_nums(__x: bytes) -> list[int]:
|
|
|
597
608
|
"""
|
|
598
609
|
if __x.isdigit():
|
|
599
610
|
return [int(__x)]
|
|
600
|
-
__x = __x.removeprefix(CSI)[
|
|
611
|
+
__x = __x.removeprefix(CSI)[
|
|
612
|
+
: idx if ~(idx := __x.find(0x6D)) else None
|
|
613
|
+
].removesuffix(b'm')
|
|
601
614
|
length = len(__x)
|
|
602
615
|
mask_indices = enumerate(
|
|
603
|
-
map(
|
|
616
|
+
map(
|
|
617
|
+
bool,
|
|
618
|
+
int.to_bytes(
|
|
619
|
+
~int.from_bytes(b';' * length) & int.from_bytes(__x), length=length
|
|
620
|
+
),
|
|
621
|
+
)
|
|
604
622
|
)
|
|
605
623
|
res = []
|
|
606
624
|
buf = bytearray()
|
|
@@ -645,7 +663,9 @@ def _iter_normalized_sgr[_T: (
|
|
|
645
663
|
)
|
|
646
664
|
|
|
647
665
|
|
|
648
|
-
def _co_yield_colorbytes(
|
|
666
|
+
def _co_yield_colorbytes(
|
|
667
|
+
__iter: Iterator[int],
|
|
668
|
+
) -> Generator[bytes | AnsiColorFormat, int, None]:
|
|
649
669
|
d: dict[int, ColorDictKeys] = {38: 'fg', 48: 'bg'}
|
|
650
670
|
obj = b''
|
|
651
671
|
while True:
|
|
@@ -737,7 +757,8 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
737
757
|
def ansi_type(self):
|
|
738
758
|
if self.is_color():
|
|
739
759
|
typ, _ = max(
|
|
740
|
-
Counter(type(x._value) for x in self if x.is_color()).items(),
|
|
760
|
+
Counter(type(x._value) for x in self if x.is_color()).items(),
|
|
761
|
+
key=lambda x: x[1],
|
|
741
762
|
)
|
|
742
763
|
return typ
|
|
743
764
|
|
|
@@ -751,7 +772,8 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
751
772
|
)
|
|
752
773
|
case ColorStr():
|
|
753
774
|
return color_chain._from_masks_unchecked(
|
|
754
|
-
[(self, ''), (other._sgr, other.base_str)],
|
|
775
|
+
[(self, ''), (other._sgr, other.base_str)],
|
|
776
|
+
self.ansi_type() or DEFAULT_ANSI,
|
|
755
777
|
)
|
|
756
778
|
case str():
|
|
757
779
|
return ColorStr(f"{self}{other}")
|
|
@@ -831,7 +853,9 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
831
853
|
elts[SgrParamBuffer(elt)] = None
|
|
832
854
|
|
|
833
855
|
self._sgr_params = list(elts)
|
|
834
|
-
self._rgb_dict = {
|
|
856
|
+
self._rgb_dict = {
|
|
857
|
+
k: v for xs in colors.values() for k, v in xs._rgb_dict.items()
|
|
858
|
+
}
|
|
835
859
|
|
|
836
860
|
def __iter__(self):
|
|
837
861
|
return iter(self._sgr_params)
|
|
@@ -850,7 +874,9 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
850
874
|
__value: ...
|
|
851
875
|
xs = list(_iter_sgr(__value))
|
|
852
876
|
if len(xs) != 1:
|
|
853
|
-
err = ValueError(
|
|
877
|
+
err = ValueError(
|
|
878
|
+
f"parsed {len(xs)} sgr parameters, expected only 1: {xs!r}"
|
|
879
|
+
)
|
|
854
880
|
raise err
|
|
855
881
|
self._sgr_params[__index] = SgrParamBuffer(xs.pop())
|
|
856
882
|
self._update_colors()
|
|
@@ -1009,19 +1035,29 @@ def _make_colorstr[_T: ColorStr](cls: type[_T], obj=_unset, *args, **kwargs) ->
|
|
|
1009
1035
|
else:
|
|
1010
1036
|
[typ] = e.args
|
|
1011
1037
|
err = TypeError(
|
|
1012
|
-
"expected integer or vector of 3 integers, "
|
|
1038
|
+
"expected integer or vector of 3 integers, "
|
|
1039
|
+
f"got {typ.__name__!r} object instead"
|
|
1013
1040
|
)
|
|
1014
1041
|
err.__cause__ = e.__cause__
|
|
1015
1042
|
raise err
|
|
1016
|
-
inst: Any = str.__new__(
|
|
1017
|
-
|
|
1043
|
+
inst: Any = str.__new__(
|
|
1044
|
+
cls, ''.join([str(sgr), base_str, SGR_RESET_S if reset else ''])
|
|
1045
|
+
)
|
|
1046
|
+
inst.__dict__ |= {
|
|
1047
|
+
'_sgr': sgr,
|
|
1048
|
+
'_base_str': base_str,
|
|
1049
|
+
'_ansi_type': ansi_type,
|
|
1050
|
+
'_reset': reset,
|
|
1051
|
+
}
|
|
1018
1052
|
return inst
|
|
1019
1053
|
|
|
1020
1054
|
|
|
1021
1055
|
class ColorStr(str):
|
|
1022
1056
|
def _weak_var_update(self, **kwargs):
|
|
1023
1057
|
if not kwargs.keys() <= {'base_str', 'sgr', 'reset'}:
|
|
1024
|
-
raise ValueError(
|
|
1058
|
+
raise ValueError(
|
|
1059
|
+
f'unexpected keys: {(kwargs.keys() - {'base_str', 'sgr', 'reset'})}'
|
|
1060
|
+
)
|
|
1025
1061
|
sgr = kwargs.get('sgr', self._sgr)
|
|
1026
1062
|
base_str = kwargs.get('base_str', self.base_str)
|
|
1027
1063
|
suffix = SGR_RESET_S if kwargs.get('reset', self.reset) else ''
|
|
@@ -1055,7 +1091,8 @@ class ColorStr(str):
|
|
|
1055
1091
|
sgr = SgrSequence(self._sgr)
|
|
1056
1092
|
sgr.rgb_dict = sgr._rgb_dict, ansi_type
|
|
1057
1093
|
inst = str.__new__(
|
|
1058
|
-
type(self),
|
|
1094
|
+
type(self),
|
|
1095
|
+
''.join([str(sgr), self.base_str, SGR_RESET_S if self.reset else '']),
|
|
1059
1096
|
)
|
|
1060
1097
|
inst.__dict__ |= vars(self) | {'_sgr': sgr, '_ansi_type': ansi_type}
|
|
1061
1098
|
return inst
|
|
@@ -1122,7 +1159,9 @@ class ColorStr(str):
|
|
|
1122
1159
|
('Red text', '0x00FF00')
|
|
1123
1160
|
"""
|
|
1124
1161
|
if not kwargs.keys() <= {'absolute', 'fg', 'bg'}:
|
|
1125
|
-
raise ValueError(
|
|
1162
|
+
raise ValueError(
|
|
1163
|
+
f"unexpected keywords: {(kwargs.keys() - {'absolute', 'fg', 'bg'})}"
|
|
1164
|
+
)
|
|
1126
1165
|
if kwargs.pop('absolute', False):
|
|
1127
1166
|
if not (args or kwargs):
|
|
1128
1167
|
return (
|
|
@@ -1167,14 +1206,18 @@ class ColorStr(str):
|
|
|
1167
1206
|
if b'%d' % SgrParameter.DOUBLE_UNDERLINE in self._sgr:
|
|
1168
1207
|
return self
|
|
1169
1208
|
elif b'%d' % SgrParameter.SINGLE_UNDERLINE in self._sgr:
|
|
1170
|
-
return self.update_sgr(
|
|
1209
|
+
return self.update_sgr(
|
|
1210
|
+
SgrParameter.SINGLE_UNDERLINE, SgrParameter.DOUBLE_UNDERLINE
|
|
1211
|
+
)
|
|
1171
1212
|
else:
|
|
1172
1213
|
return self.update_sgr(SgrParameter.DOUBLE_UNDERLINE)
|
|
1173
1214
|
else:
|
|
1174
1215
|
if b'%d' % SgrParameter.SINGLE_UNDERLINE in self._sgr:
|
|
1175
1216
|
return self
|
|
1176
1217
|
elif b'%d' % SgrParameter.DOUBLE_UNDERLINE in self._sgr:
|
|
1177
|
-
return self.update_sgr(
|
|
1218
|
+
return self.update_sgr(
|
|
1219
|
+
SgrParameter.DOUBLE_UNDERLINE, SgrParameter.SINGLE_UNDERLINE
|
|
1220
|
+
)
|
|
1178
1221
|
else:
|
|
1179
1222
|
return self.update_sgr(SgrParameter.SINGLE_UNDERLINE)
|
|
1180
1223
|
|
|
@@ -1245,7 +1288,8 @@ class ColorStr(str):
|
|
|
1245
1288
|
else:
|
|
1246
1289
|
sgr.append(bx)
|
|
1247
1290
|
inst = super().__new__(
|
|
1248
|
-
type(self),
|
|
1291
|
+
type(self),
|
|
1292
|
+
''.join([str(sgr), self.base_str, SGR_RESET_S if self.reset else '']),
|
|
1249
1293
|
)
|
|
1250
1294
|
inst.__dict__ |= vars(self) | {
|
|
1251
1295
|
'_sgr': sgr,
|
|
@@ -1321,7 +1365,9 @@ class ColorStr(str):
|
|
|
1321
1365
|
|
|
1322
1366
|
def join(self, __iterable):
|
|
1323
1367
|
return self._weak_var_update(
|
|
1324
|
-
base_str=self.base_str.join(
|
|
1368
|
+
base_str=self.base_str.join(
|
|
1369
|
+
getattr(elt, 'base_str', elt) for elt in __iterable
|
|
1370
|
+
)
|
|
1325
1371
|
)
|
|
1326
1372
|
|
|
1327
1373
|
def ljust(self, __width, __fillchar=" "):
|
|
@@ -1334,7 +1380,9 @@ class ColorStr(str):
|
|
|
1334
1380
|
return self._weak_var_update(base_str=self.base_str.lstrip(__chars))
|
|
1335
1381
|
|
|
1336
1382
|
def partition(self, __sep):
|
|
1337
|
-
lhs, sep, rhs = (
|
|
1383
|
+
lhs, sep, rhs = (
|
|
1384
|
+
self._weak_var_update(base_str=s) for s in self.base_str.partition(__sep)
|
|
1385
|
+
)
|
|
1338
1386
|
return lhs, sep, rhs
|
|
1339
1387
|
|
|
1340
1388
|
def removeprefix(self, __prefix):
|
|
@@ -1344,7 +1392,9 @@ class ColorStr(str):
|
|
|
1344
1392
|
return self._weak_var_update(base_str=self.base_str.removesuffix(__prefix))
|
|
1345
1393
|
|
|
1346
1394
|
def replace(self, __old, __new, __count=-1):
|
|
1347
|
-
return self._weak_var_update(
|
|
1395
|
+
return self._weak_var_update(
|
|
1396
|
+
base_str=self.base_str.replace(__old, __new, __count)
|
|
1397
|
+
)
|
|
1348
1398
|
|
|
1349
1399
|
def rfind(self, __sub, *args):
|
|
1350
1400
|
return self.base_str.rfind(__sub, *args)
|
|
@@ -1359,7 +1409,9 @@ class ColorStr(str):
|
|
|
1359
1409
|
return self._weak_var_update(base_str=self.base_str.rstrip(__chars))
|
|
1360
1410
|
|
|
1361
1411
|
def rpartition(self, __sep):
|
|
1362
|
-
lhs, sep, rhs = (
|
|
1412
|
+
lhs, sep, rhs = (
|
|
1413
|
+
self._weak_var_update(base_str=s) for s in self.base_str.rpartition(__sep)
|
|
1414
|
+
)
|
|
1363
1415
|
return lhs, sep, rhs
|
|
1364
1416
|
|
|
1365
1417
|
def rsplit(self, sep=None, maxsplit=-1):
|
|
@@ -1376,7 +1428,8 @@ class ColorStr(str):
|
|
|
1376
1428
|
|
|
1377
1429
|
def splitlines(self, keepends=False):
|
|
1378
1430
|
return [
|
|
1379
|
-
self._weak_var_update(base_str=s)
|
|
1431
|
+
self._weak_var_update(base_str=s)
|
|
1432
|
+
for s in self.base_str.splitlines(keepends=keepends)
|
|
1380
1433
|
]
|
|
1381
1434
|
|
|
1382
1435
|
def startswith(self, __prefix, *args):
|
|
@@ -1476,11 +1529,15 @@ class ColorStr(str):
|
|
|
1476
1529
|
k: L['fg', 'bg']
|
|
1477
1530
|
if isinstance(other, type(self)):
|
|
1478
1531
|
xor_dict = {
|
|
1479
|
-
k: int2rgb(
|
|
1532
|
+
k: int2rgb(
|
|
1533
|
+
Color.from_rgb(self.rgb_dict[k]) ^ Color.from_rgb(other.rgb_dict[k])
|
|
1534
|
+
)
|
|
1480
1535
|
for k in self.rgb_dict.keys() & other.rgb_dict
|
|
1481
1536
|
}
|
|
1482
1537
|
elif isinstance(other, int):
|
|
1483
|
-
xor_dict = {
|
|
1538
|
+
xor_dict = {
|
|
1539
|
+
k: int2rgb(Color.from_rgb(v) ^ other) for k, v in self.rgb_dict.items()
|
|
1540
|
+
}
|
|
1484
1541
|
else:
|
|
1485
1542
|
return NotImplemented
|
|
1486
1543
|
if not xor_dict:
|
|
@@ -1596,7 +1653,10 @@ class color_chain:
|
|
|
1596
1653
|
elif isinstance(other, str):
|
|
1597
1654
|
if len(self._masks) > 0:
|
|
1598
1655
|
return self._from_masks_unchecked(
|
|
1599
|
-
[
|
|
1656
|
+
[
|
|
1657
|
+
*self.masks[:-1],
|
|
1658
|
+
(self._masks[-1][0], self._masks[-1][1] + other),
|
|
1659
|
+
],
|
|
1600
1660
|
ansi_type=self._ansi_type,
|
|
1601
1661
|
)
|
|
1602
1662
|
return self._from_masks_unchecked(
|
|
@@ -1615,7 +1675,9 @@ class color_chain:
|
|
|
1615
1675
|
if not kwargs.keys() <= {'fg', 'bg'}:
|
|
1616
1676
|
raise ValueError
|
|
1617
1677
|
sgr = SgrSequence(__sgr)
|
|
1618
|
-
sgr.rgb_dict = {
|
|
1678
|
+
sgr.rgb_dict = {
|
|
1679
|
+
k: v for k, v in kwargs.items() if v is not None
|
|
1680
|
+
}, self._ansi_type
|
|
1619
1681
|
self._masks = [(sgr, '')]
|
|
1620
1682
|
|
|
1621
1683
|
def __radd__(self, other):
|
chromatic/color/core.pyi
CHANGED
|
@@ -96,7 +96,9 @@ class colorbytes(bytes):
|
|
|
96
96
|
RGBVectorLike,
|
|
97
97
|
)](
|
|
98
98
|
cls: type[_T],
|
|
99
|
-
__rgb:
|
|
99
|
+
__rgb: (
|
|
100
|
+
tuple[ColorDictKeys, _VT] | Mapping[L['fg'], _VT] | Mapping[L['bg'], _VT]
|
|
101
|
+
),
|
|
100
102
|
) -> _T: ...
|
|
101
103
|
@classmethod
|
|
102
104
|
@overload
|
|
@@ -118,7 +120,9 @@ class colorbytes(bytes):
|
|
|
118
120
|
@property
|
|
119
121
|
def rgb_dict(
|
|
120
122
|
self,
|
|
121
|
-
) ->
|
|
123
|
+
) -> (
|
|
124
|
+
MappingProxyType[L['fg'], Int3Tuple] | MappingProxyType[L['bg'], Int3Tuple]
|
|
125
|
+
): ...
|
|
122
126
|
|
|
123
127
|
class ColorStr(str):
|
|
124
128
|
def _weak_var_update(self, **kwargs: Unpack[_ColorStrWeakVars]) -> Self: ...
|
|
@@ -138,7 +142,11 @@ class ColorStr(str):
|
|
|
138
142
|
def casefold(self) -> Self: ...
|
|
139
143
|
def center(self, width, fillchar=' ') -> Self: ...
|
|
140
144
|
def count(
|
|
141
|
-
self,
|
|
145
|
+
self,
|
|
146
|
+
x: str,
|
|
147
|
+
__start: SupportsIndex | None = ...,
|
|
148
|
+
__end: SupportsIndex | None = ...,
|
|
149
|
+
/,
|
|
142
150
|
): ...
|
|
143
151
|
def endswith(
|
|
144
152
|
self,
|
|
@@ -149,12 +157,20 @@ class ColorStr(str):
|
|
|
149
157
|
) -> bool: ...
|
|
150
158
|
def expandtabs(self, /, tabsize=8) -> Self: ...
|
|
151
159
|
def find(
|
|
152
|
-
self,
|
|
160
|
+
self,
|
|
161
|
+
__sub: str,
|
|
162
|
+
__start: SupportsIndex | None = ...,
|
|
163
|
+
__end: SupportsIndex | None = ...,
|
|
164
|
+
/,
|
|
153
165
|
) -> int: ...
|
|
154
166
|
def format(self, *args, **kwargs) -> Self: ...
|
|
155
167
|
def format_map(self, __mapping: Mapping[str, object], /) -> Self: ...
|
|
156
168
|
def index(
|
|
157
|
-
self,
|
|
169
|
+
self,
|
|
170
|
+
__sub: str,
|
|
171
|
+
__start: SupportsIndex | None = ...,
|
|
172
|
+
__end: SupportsIndex | None = ...,
|
|
173
|
+
/,
|
|
158
174
|
) -> int: ...
|
|
159
175
|
def join(self, __iterable: Iterable[str]) -> Self: ...
|
|
160
176
|
def ljust(self, __width: SupportsIndex, __fillchar=' ') -> Self: ...
|
|
@@ -165,10 +181,18 @@ class ColorStr(str):
|
|
|
165
181
|
def removesuffix(self, __suffix: str, /) -> Self: ...
|
|
166
182
|
def replace(self, __old: str, __new: str, __count: SupportsIndex = -1) -> Self: ...
|
|
167
183
|
def rfind(
|
|
168
|
-
self,
|
|
184
|
+
self,
|
|
185
|
+
__sub: str,
|
|
186
|
+
__start: SupportsIndex | None = ...,
|
|
187
|
+
__end: SupportsIndex | None = ...,
|
|
188
|
+
/,
|
|
169
189
|
) -> int: ...
|
|
170
190
|
def rindex(
|
|
171
|
-
self,
|
|
191
|
+
self,
|
|
192
|
+
__sub: str,
|
|
193
|
+
__start: SupportsIndex | None = ...,
|
|
194
|
+
__end: SupportsIndex | None = ...,
|
|
195
|
+
/,
|
|
172
196
|
) -> int: ...
|
|
173
197
|
def rjust(self, __width: SupportsIndex, __fillchar=' ') -> Self: ...
|
|
174
198
|
def rpartition(self, __sep: str) -> TupleOf3[Self]: ...
|
|
@@ -255,16 +279,30 @@ class color_chain:
|
|
|
255
279
|
) -> Self: ...
|
|
256
280
|
@classmethod
|
|
257
281
|
def from_masks(
|
|
258
|
-
cls,
|
|
282
|
+
cls,
|
|
283
|
+
masks: Sequence[tuple[SgrSequence, str]],
|
|
284
|
+
ansi_type: type[AnsiColorFormat] = None,
|
|
259
285
|
) -> Self: ...
|
|
260
|
-
def __add__[_T: (
|
|
286
|
+
def __add__[_T: (
|
|
287
|
+
color_chain,
|
|
288
|
+
SgrSequence,
|
|
289
|
+
ColorStr,
|
|
290
|
+
str,
|
|
291
|
+
)](self, other: _T) -> color_chain: ...
|
|
261
292
|
def __call__(self, __obj=None) -> str: ...
|
|
262
293
|
def __init__[_T: (
|
|
263
294
|
int,
|
|
264
295
|
Buffer,
|
|
265
296
|
SgrParamBuffer,
|
|
266
|
-
)](
|
|
267
|
-
|
|
297
|
+
)](
|
|
298
|
+
self, __sgr: Iterable[_T] = ..., **kwargs: Unpack[_ColorChainKwargs]
|
|
299
|
+
) -> None: ...
|
|
300
|
+
def __radd__[_T: (
|
|
301
|
+
color_chain,
|
|
302
|
+
SgrSequence,
|
|
303
|
+
ColorStr,
|
|
304
|
+
str,
|
|
305
|
+
)](self, other: _T) -> color_chain: ...
|
|
268
306
|
|
|
269
307
|
_ansi_type: type[AnsiColorFormat]
|
|
270
308
|
_masks: list[tuple[SgrSequence, str]]
|
|
@@ -355,7 +393,9 @@ class SgrParamBuffer[
|
|
|
355
393
|
def is_reset(self) -> bool: ...
|
|
356
394
|
def __buffer__(self, __flags: int) -> memoryview: ...
|
|
357
395
|
def __bytes__(self) -> bytes: ...
|
|
358
|
-
def __eq__[_T](
|
|
396
|
+
def __eq__[_T](
|
|
397
|
+
self: SgrParamBuffer[_T], other
|
|
398
|
+
) -> TypeIs[SgrParamBuffer[_T] | _T]: ...
|
|
359
399
|
def __hash__(self) -> int: ...
|
|
360
400
|
@overload
|
|
361
401
|
def __new__(cls, __value: _T = ...) -> Self: ...
|
|
@@ -394,14 +434,20 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
394
434
|
@overload
|
|
395
435
|
def __getitem__(self, __index: SupportsIndex) -> SgrParamBuffer: ...
|
|
396
436
|
@overload
|
|
397
|
-
def __setitem__(
|
|
437
|
+
def __setitem__(
|
|
438
|
+
self, __index: slice, __value: Iterable[bytes | SgrParamBuffer]
|
|
439
|
+
): ...
|
|
398
440
|
@overload
|
|
399
441
|
def __setitem__(self, __index: SupportsIndex, __value: bytes | SgrParamBuffer): ...
|
|
400
442
|
@overload
|
|
401
443
|
def __delitem__(self, __index: slice): ...
|
|
402
444
|
@overload
|
|
403
445
|
def __delitem__(self, __index: SupportsIndex): ...
|
|
404
|
-
def __init__[_T: (
|
|
446
|
+
def __init__[_T: (
|
|
447
|
+
int,
|
|
448
|
+
Buffer,
|
|
449
|
+
SgrParamBuffer,
|
|
450
|
+
)](self, __iter: Iterable[_T] = ...): ...
|
|
405
451
|
def __iter__(self) -> Iterator[SgrParamBuffer]: ...
|
|
406
452
|
|
|
407
453
|
__slots__ = '_rgb_dict', '_sgr_params'
|
|
@@ -421,7 +467,9 @@ class SgrSequence(MutableSequence[SgrParamBuffer]):
|
|
|
421
467
|
def rgb_dict(self, __value: dict[ColorDictKeys, Int3Tuple | None]): ...
|
|
422
468
|
@overload
|
|
423
469
|
@rgb_dict.setter # type: ignore[no-redef]
|
|
424
|
-
def rgb_dict(
|
|
470
|
+
def rgb_dict(
|
|
471
|
+
self, __value: tuple[dict[ColorDictKeys, Int3Tuple | None], AnsiColorType]
|
|
472
|
+
): ...
|
|
425
473
|
|
|
426
474
|
class _RecolorKwargs(TypedDict, total=False):
|
|
427
475
|
absolute: bool
|