chromatic-python 0.1.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.
@@ -0,0 +1,693 @@
1
+ from functools import lru_cache, update_wrapper, wraps
2
+ from inspect import getfullargspec, signature
3
+ from types import FunctionType, MappingProxyType
4
+ from typing import (
5
+ Callable, cast, dataclass_transform, Iterable, Iterator, Sequence, TYPE_CHECKING, TypedDict,
6
+ Union,
7
+ Unpack
8
+ )
9
+
10
+ from .colorconv import hex2rgb
11
+ from .core import (
12
+ AnsiColorFormat, Color, ColorStr, DEFAULT_ANSI, get_ansi_type, SgrParameter, SgrSequence
13
+ )
14
+ from .._typing import AnsiColorAlias, Int3Tuple
15
+
16
+ null = object()
17
+
18
+
19
+ class Member[_T]:
20
+
21
+ def __init__(self, name, clsname, offset):
22
+ self.name = name
23
+ self.clsname = clsname
24
+ self.offset = offset
25
+
26
+ def __get__(self, instance, owner) -> _T:
27
+ if instance is None:
28
+ return self
29
+ value = instance.__members__[self.offset]
30
+ if value is null:
31
+ raise AttributeError(self.name)
32
+ try:
33
+ value.name = self.name
34
+ except AttributeError:
35
+ pass
36
+ return value
37
+
38
+ def __set__(self, instance, value: _T):
39
+ instance.__members__[self.offset] = value
40
+
41
+ def __repr__(self):
42
+ return f"<{type(self).__name__} {self.name!r} of {self.clsname!r}>"
43
+
44
+
45
+ @dataclass_transform()
46
+ class DynamicNSMeta[_VT](type):
47
+
48
+ def __new__(mcls, clsname: str, bases: tuple[type, ...], mapping: dict[str, ...], **kwargs):
49
+ slot_names: dict[str, ...] = mapping.get('__annotations__', {})
50
+ member: Member[_VT]
51
+ for offset, name in enumerate(slot_names):
52
+ member = Member(name, clsname, offset)
53
+ mapping[name] = member
54
+ return type.__new__(mcls, clsname, bases, mapping, **kwargs)
55
+
56
+
57
+ class DynamicNamespace[_VT](metaclass=DynamicNSMeta[_VT]):
58
+ if TYPE_CHECKING:
59
+ __members__: list[_VT]
60
+
61
+ def __new__(cls, *args, **kwargs):
62
+ inst = super().__new__(cls)
63
+ if hasattr(cls, '__annotations__'):
64
+ is_member = _check_if_ns_member(cls)
65
+ slots = kwargs.pop('slots', list(filter(is_member, cls.__annotations__)))
66
+ empty_slots = [null] * len(slots)
67
+ object.__setattr__(inst, '__members__', empty_slots)
68
+ return inst
69
+
70
+ def __init__[_KT](self, **kwargs: dict[_KT, _VT]):
71
+ for name, value in kwargs.items():
72
+ self.__setattr__(name, value)
73
+
74
+ def __init_subclass__(cls, **kwargs):
75
+ if DynamicNamespace in cls.__bases__:
76
+ return super().__new__(cls)
77
+ factory: Callable[[...], _VT] | FunctionType = kwargs.get('factory')
78
+ if not callable(factory):
79
+ raise ValueError(
80
+ f"{cls.__name__!r} does not inherit {DynamicNamespace.__name__!r} as a "
81
+ f"base class "
82
+ f"and does not provide callable 'factory' keyword argument")
83
+ base: type[DynamicNamespace] = cast(
84
+ type[...], next(
85
+ (typ for typ in cls.mro()
86
+ if DynamicNamespace in typ.__bases__), null))
87
+ if base is null:
88
+ raise TypeError(
89
+ f"{cls.__qualname__!r} does not have any base classes of "
90
+ f"type {DynamicNamespace.__qualname__!r}") from None
91
+ d = dict(zip(base.__annotations__, map(factory, base().__members__)))
92
+ cls.__annotations__: dict[str, ...] = {k: type(v) for k, v in d.items()}
93
+ new = cls.__new__
94
+
95
+ @wraps(cls.__new__)
96
+ def wrapped_new(*args, **kw):
97
+ return new(*args, **(kw | dict(slots=d)))
98
+
99
+ @wraps(cls.__init__)
100
+ def wrapped_init(*args, **kw):
101
+ return DynamicNamespace.__init__(*args, **(kw | d))
102
+
103
+ cls.__new__ = wrapped_new
104
+ cls.__init__ = wrapped_init
105
+ return super().__new__(cls)
106
+
107
+ def __setattr__(self, name, value):
108
+ cls = type(self)
109
+ if hasattr(cls, '__annotations__') and name not in cls.__annotations__:
110
+ raise AttributeError(
111
+ f'{cls.__name__!r} object has no attribute {name!r}') from None
112
+ super().__setattr__(name, value)
113
+
114
+ def as_dict(self):
115
+ cls = type(self)
116
+ return dict(zip(cls.__annotations__, self.__members__))
117
+
118
+ def __iter__(self):
119
+ return iter(self.__members__)
120
+
121
+
122
+ def _check_if_ns_member(cls: type) -> Callable[[str], bool]:
123
+ type_params = cls.__type_params__
124
+ if type_params and len(type_params) == 1:
125
+ anno_dict = cls.__annotations__
126
+ member_type = type_params[0]
127
+
128
+ def f(x: str):
129
+ return member_type == anno_dict.get(x)
130
+
131
+ return f
132
+ else:
133
+ return lambda _: False
134
+
135
+
136
+ def _ns_from_iter[_KT, _VT](
137
+ __iter: Iterator[_KT] | Callable[[], Iterator[_KT]], member_type: _VT = null
138
+ ) -> Callable[[type[DynamicNamespace[_VT]]], type[DynamicNamespace[_VT]]]:
139
+ def decorator(cls: type[DynamicNamespace[_VT]]):
140
+ anno = cls.__annotations__
141
+ type_params = cls.__type_params__
142
+ m_iter = __iter() if callable(__iter) else iter(__iter)
143
+ members: Iterator[_KT] = m_iter if member_type == null else map(member_type, m_iter)
144
+ d = dict(zip((k for k, v in anno.items() if v in type_params), members))
145
+
146
+ @wraps(cls.__init__)
147
+ def wrapped(*args, **kwargs):
148
+ return cls.__base__.__init__(*args, **(kwargs | d))
149
+
150
+ cls.__init__ = wrapped
151
+ return cls
152
+
153
+ return decorator
154
+
155
+
156
+ def _gen_named_color_values() -> Iterator[int]:
157
+ yield from [
158
+ 0x000000, 0x696969, 0x808080, 0xa9a9a9, 0xc0c0c0, 0xd3d3d3, 0xf5f5f5, 0xffffff, 0x800000,
159
+ 0x8b0000, 0xff0000, 0xb22222, 0xa52a2a, 0xcd5c5c, 0xf08080, 0xbc8f8f, 0xffe4e1, 0xfffafa,
160
+ 0xa0522d, 0xff4500, 0xff6347, 0xea7e5d, 0xff7f50, 0xfa8072, 0xe9967a, 0xffa07a, 0xfff5ee,
161
+ 0x8b4513, 0xd2691e, 0xcd853f, 0xf4a460, 0xffdab9, 0xfaf0e6, 0xff8c00, 0xdeb887, 0xffe4c4,
162
+ 0xfaebd7, 0xffa500, 0xd2b48c, 0xf5deb3, 0xffdead, 0xffe4b5, 0xffebcd, 0xffefd5, 0xfdf5e6,
163
+ 0xfffaf0, 0xb8860b, 0xdaa520, 0xfff8dc, 0xbdb76b, 0xffd700, 0xf0e68c, 0xeee8aa, 0xf5f5dc,
164
+ 0xfafad2, 0xfffacd, 0x808000, 0xffff00, 0xffffe0, 0xfffff0, 0x006400, 0x008000, 0x556b2f,
165
+ 0x228b22, 0x6b8e23, 0x32cd32, 0x8fbc8f, 0x00ff00, 0x9acd32, 0x7cfc00, 0x7fff00, 0x90ee90,
166
+ 0xadff2f, 0x98fb98, 0xf0fff0, 0x2e8b57, 0x3cb371, 0x00ff7f, 0xf5fffa, 0x2f4f4f, 0x008080,
167
+ 0x008b8b, 0x20b2aa, 0x48d1cc, 0x66cdaa, 0x40e0d0, 0x00fa9a, 0x00ffff, 0xafeeee, 0x7fffd4,
168
+ 0xe0ffff, 0xf0ffff, 0x4682b4, 0x5f9ea0, 0x00bfff, 0x00ced1, 0x87ceeb, 0x87cefa, 0xadd8e6,
169
+ 0xb0e0e6, 0xf0f8ff, 0x191970, 0x4169e1, 0x708090, 0x1e90ff, 0x778899, 0x6495ed, 0xb0c4de,
170
+ 0xe6e6fa, 0x000080, 0x00008b, 0x0000cd, 0x0000ff, 0xf8f8ff, 0x4b0082, 0x9400d3, 0x483d8b,
171
+ 0x663399, 0x8a2be2, 0x9932cc, 0x6a5acd, 0xba55d3, 0x7b68ee, 0x9370db, 0xd8bfd8, 0x800080,
172
+ 0x8b008b, 0xc71585, 0xff00ff, 0xff1493, 0xda70d6, 0xff69b4, 0xee82ee, 0xdda0dd, 0xfff0f5,
173
+ 0xdc143c, 0xdb7093, 0xffb6c1, 0xffc0cb]
174
+
175
+
176
+ @_ns_from_iter(_gen_named_color_values, Color)
177
+ class ColorNamespace[NamedColor: Color](DynamicNamespace[NamedColor]):
178
+ BLACK: NamedColor
179
+ DIM_GREY: NamedColor
180
+ GREY: NamedColor
181
+ DARK_GREY: NamedColor
182
+ SILVER: NamedColor
183
+ LIGHT_GREY: NamedColor
184
+ WHITE_SMOKE: NamedColor
185
+ WHITE: NamedColor
186
+ MAROON: NamedColor
187
+ DARK_RED: NamedColor
188
+ RED: NamedColor
189
+ FIREBRICK: NamedColor
190
+ BROWN: NamedColor
191
+ INDIAN_RED: NamedColor
192
+ LIGHT_CORAL: NamedColor
193
+ ROSY_BROWN: NamedColor
194
+ MISTY_ROSE: NamedColor
195
+ SNOW: NamedColor
196
+ SIENNA: NamedColor
197
+ ORANGE_RED: NamedColor
198
+ TOMATO: NamedColor
199
+ BURNT_SIENNA: NamedColor
200
+ CORAL: NamedColor
201
+ SALMON: NamedColor
202
+ DARK_SALMON: NamedColor
203
+ LIGHT_SALMON: NamedColor
204
+ SEASHELL: NamedColor
205
+ SADDLE_BROWN: NamedColor
206
+ CHOCOLATE: NamedColor
207
+ PERU: NamedColor
208
+ SANDY_BROWN: NamedColor
209
+ PEACH_PUFF: NamedColor
210
+ LINEN: NamedColor
211
+ DARK_ORANGE: NamedColor
212
+ BURLY_WOOD: NamedColor
213
+ BISQUE: NamedColor
214
+ ANTIQUE_WHITE: NamedColor
215
+ ORANGE: NamedColor
216
+ TAN: NamedColor
217
+ WHEAT: NamedColor
218
+ NAVAJO_WHITE: NamedColor
219
+ MOCCASIN: NamedColor
220
+ BLANCHED_ALMOND: NamedColor
221
+ PAPAYA_WHIP: NamedColor
222
+ OLD_LACE: NamedColor
223
+ FLORAL_WHITE: NamedColor
224
+ DARK_GOLDENROD: NamedColor
225
+ GOLDENROD: NamedColor
226
+ CORNSILK: NamedColor
227
+ DARK_KHAKI: NamedColor
228
+ GOLD: NamedColor
229
+ KHAKI: NamedColor
230
+ PALE_GOLDENROD: NamedColor
231
+ BEIGE: NamedColor
232
+ LIGHT_GOLDENROD_YELLOW: NamedColor
233
+ LEMON_CHIFFON: NamedColor
234
+ OLIVE: NamedColor
235
+ YELLOW: NamedColor
236
+ LIGHT_YELLOW: NamedColor
237
+ IVORY: NamedColor
238
+ DARK_GREEN: NamedColor
239
+ GREEN: NamedColor
240
+ DARK_OLIVE_GREEN: NamedColor
241
+ FOREST_GREEN: NamedColor
242
+ OLIVE_DRAB: NamedColor
243
+ LIME_GREEN: NamedColor
244
+ DARK_SEA_GREEN: NamedColor
245
+ LIME: NamedColor
246
+ YELLOW_GREEN: NamedColor
247
+ LAWN_GREEN: NamedColor
248
+ CHARTREUSE: NamedColor
249
+ LIGHT_GREEN: NamedColor
250
+ GREEN_YELLOW: NamedColor
251
+ PALE_GREEN: NamedColor
252
+ HONEYDEW: NamedColor
253
+ SEA_GREEN: NamedColor
254
+ MEDIUM_SEA_GREEN: NamedColor
255
+ SPRING_GREEN: NamedColor
256
+ MINT_CREAM: NamedColor
257
+ DARK_SLATE_GREY: NamedColor
258
+ TEAL: NamedColor
259
+ DARK_CYAN: NamedColor
260
+ LIGHT_SEA_GREEN: NamedColor
261
+ MEDIUM_TURQUOISE: NamedColor
262
+ MEDIUM_AQUAMARINE: NamedColor
263
+ TURQUOISE: NamedColor
264
+ MEDIUM_SPRING_GREEN: NamedColor
265
+ CYAN: NamedColor
266
+ PALE_TURQUOISE: NamedColor
267
+ AQUAMARINE: NamedColor
268
+ LIGHT_CYAN: NamedColor
269
+ AZURE: NamedColor
270
+ STEEL_BLUE: NamedColor
271
+ CADET_BLUE: NamedColor
272
+ DEEP_SKY_BLUE: NamedColor
273
+ DARK_TURQUOISE: NamedColor
274
+ SKY_BLUE: NamedColor
275
+ LIGHT_SKY_BLUE: NamedColor
276
+ LIGHT_BLUE: NamedColor
277
+ POWDER_BLUE: NamedColor
278
+ ALICE_BLUE: NamedColor
279
+ MIDNIGHT_BLUE: NamedColor
280
+ ROYAL_BLUE: NamedColor
281
+ SLATE_GREY: NamedColor
282
+ DODGER_BLUE: NamedColor
283
+ LIGHT_SLATE_GREY: NamedColor
284
+ CORNFLOWER_BLUE: NamedColor
285
+ LIGHT_STEEL_BLUE: NamedColor
286
+ LAVENDER: NamedColor
287
+ NAVY: NamedColor
288
+ DARK_BLUE: NamedColor
289
+ MEDIUM_BLUE: NamedColor
290
+ BLUE: NamedColor
291
+ GHOST_WHITE: NamedColor
292
+ INDIGO: NamedColor
293
+ DARK_VIOLET: NamedColor
294
+ DARK_SLATE_BLUE: NamedColor
295
+ REBECCA_PURPLE: NamedColor
296
+ BLUE_VIOLET: NamedColor
297
+ DARK_ORCHID: NamedColor
298
+ SLATE_BLUE: NamedColor
299
+ MEDIUM_ORCHID: NamedColor
300
+ MEDIUM_SLATE_BLUE: NamedColor
301
+ MEDIUM_PURPLE: NamedColor
302
+ THISTLE: NamedColor
303
+ PURPLE: NamedColor
304
+ DARK_MAGENTA: NamedColor
305
+ MEDIUM_VIOLET_RED: NamedColor
306
+ FUCHSIA: NamedColor
307
+ DEEP_PINK: NamedColor
308
+ ORCHID: NamedColor
309
+ HOT_PINK: NamedColor
310
+ VIOLET: NamedColor
311
+ PLUM: NamedColor
312
+ LAVENDER_BLUSH: NamedColor
313
+ CRIMSON: NamedColor
314
+ PALE_VIOLET_RED: NamedColor
315
+ LIGHT_PINK: NamedColor
316
+ PINK: NamedColor
317
+
318
+
319
+ # noinspection PyTypedDict
320
+ class _ColorStrWrapperKwargs(TypedDict, total=False):
321
+ ansi_type: Union[AnsiColorAlias, type[AnsiColorFormat]]
322
+ bg: Union[Color, tuple[int, int, int], int]
323
+ fg: Union[Color, tuple[int, int, int], int]
324
+ sgr_params: Sequence[Union[int, SgrParameter]]
325
+
326
+
327
+ # noinspection PyUnresolvedReferences
328
+ class color_str_wrapper:
329
+
330
+ def __init__(self, **kwargs: Unpack[_ColorStrWrapperKwargs]):
331
+ self._rhs_ = kwargs.get('_rhs_', False)
332
+ self._concat_ = kwargs.get('_concat_', '')
333
+ if typ := kwargs.get('ansi_type'):
334
+ self._ansi_type_ = get_ansi_type(typ)
335
+ else:
336
+ self._ansi_type_ = DEFAULT_ANSI
337
+ if params := kwargs.get('sgr_params'):
338
+ self._sgr_ = SgrSequence(params)
339
+ else:
340
+ self._sgr_ = SgrSequence()
341
+ for k in kwargs.keys() & {'fg', 'bg'}:
342
+ if v := kwargs[k]:
343
+ if not isinstance(v, Iterable):
344
+ v = hex2rgb(v)
345
+ self._sgr_ += SgrSequence(self._ansi_type_.from_rgb({k: v}))
346
+
347
+ def __call__(self, __obj=None):
348
+ if type(self) is type(__obj):
349
+ new_sgr = self._sgr_ + __obj._sgr_
350
+ new_kwargs = {
351
+ 'ansi_type': self._ansi_type_,
352
+ '_concat_': self.__dict__.get('_concat_', '').removesuffix(
353
+ str(self._sgr_)) + str(new_sgr),
354
+ '_rhs_': self.__dict__['_rhs_'],
355
+ **new_sgr.rgb_dict}
356
+ new_kwargs['sgr_params'] = [
357
+ int(v._value_) for v in new_sgr if not v.is_color()
358
+ ]
359
+ return color_str_wrapper(**new_kwargs)
360
+ if isinstance(__obj, ColorStr):
361
+ if getattr(self, '_rhs_', False):
362
+ new_kwargs = {
363
+ 'ansi_type': self._ansi_type_,
364
+ 'sgr_params': list(self._sgr_),
365
+ '_concat_': (
366
+ getattr(self, '_concat_', '') + __obj
367
+ ).removesuffix(''),
368
+ '_rhs_': True,
369
+ **self._sgr_.rgb_dict
370
+ }
371
+ return color_str_wrapper(**new_kwargs)
372
+ new_params = [v for v in __obj._sgr_.values() if v not in self._sgr_.values()]
373
+ return ColorStr(
374
+ __obj.base_str,
375
+ color_spec=SgrSequence(new_params),
376
+ no_reset=__obj.no_reset,
377
+ ansi_type=self._ansi_type_)
378
+ if getattr(self, '_rhs_', False):
379
+ new_kwargs = {
380
+ 'ansi_type': self._ansi_type_,
381
+ 'sgr_params': list(self._sgr_),
382
+ '_concat_': (
383
+ getattr(self, '_concat_', '') + f"{__obj}"
384
+ ).removesuffix(''),
385
+ '_rhs_': True,
386
+ **self._sgr_.rgb_dict
387
+ }
388
+ return color_str_wrapper(**new_kwargs)
389
+ return ColorStr(__obj, color_spec=self._sgr_, ansi_type=self._ansi_type_)
390
+
391
+ def __add__(self, other):
392
+ return self.__call__(other)
393
+
394
+ def __radd__(self, other):
395
+ if getattr(self, '_rhs_') is False and type(other) is ColorStr:
396
+ setattr(self, '_rhs_', True)
397
+ return self.__call__(other)
398
+
399
+ def __str__(self):
400
+ return self.__dict__['_concat_'] + str(self._sgr_)
401
+
402
+ def __repr__(self):
403
+ return (f"{type(self).__name__}"
404
+ f"(sgr_params={self._sgr_.values()}, ansi_type={self._ansi_type_.__name__})")
405
+
406
+ def __getattr__(self, name):
407
+ if hasattr(str, name):
408
+ return getattr(self.__str__(), name)
409
+ raise AttributeError
410
+
411
+
412
+ def _style_wrappers():
413
+ yield from (
414
+ color_str_wrapper()
415
+ if x in {38, 48}
416
+ else color_str_wrapper(sgr_params=[x])
417
+ for x in SgrParameter
418
+ )
419
+
420
+
421
+ @_ns_from_iter(_style_wrappers)
422
+ class AnsiStyle[StyleStr: color_str_wrapper](DynamicNamespace[StyleStr]):
423
+ RESET: StyleStr
424
+ BOLD: StyleStr
425
+ FAINT: StyleStr
426
+ ITALICS: StyleStr
427
+ SINGLE_UNDERLINE: StyleStr
428
+ SLOW_BLINK: StyleStr
429
+ RAPID_BLINK: StyleStr
430
+ NEGATIVE: StyleStr
431
+ CONCEALED_CHARS: StyleStr
432
+ CROSSED_OUT: StyleStr
433
+ PRIMARY: StyleStr
434
+ FIRST_ALT: StyleStr
435
+ SECOND_ALT: StyleStr
436
+ THIRD_ALT: StyleStr
437
+ FOURTH_ALT: StyleStr
438
+ FIFTH_ALT: StyleStr
439
+ SIXTH_ALT: StyleStr
440
+ SEVENTH_ALT: StyleStr
441
+ EIGHTH_ALT: StyleStr
442
+ NINTH_ALT: StyleStr
443
+ GOTHIC: StyleStr
444
+ DOUBLE_UNDERLINE: StyleStr
445
+ RESET_BOLD_AND_FAINT: StyleStr
446
+ RESET_ITALIC_AND_GOTHIC: StyleStr
447
+ RESET_UNDERLINES: StyleStr
448
+ RESET_BLINKING: StyleStr
449
+ POSITIVE: StyleStr
450
+ REVEALED_CHARS: StyleStr
451
+ RESET_CROSSED_OUT: StyleStr
452
+ BLACK_FG: StyleStr
453
+ RED_FG: StyleStr
454
+ GREEN_FG: StyleStr
455
+ YELLOW_FG: StyleStr
456
+ BLUE_FG: StyleStr
457
+ MAGENTA_FG: StyleStr
458
+ CYAN_FG: StyleStr
459
+ WHITE_FG: StyleStr
460
+ ANSI_256_SET_FG: StyleStr
461
+ DEFAULT_FG_COLOR: StyleStr
462
+ BLACK_BG: StyleStr
463
+ RED_BG: StyleStr
464
+ GREEN_BG: StyleStr
465
+ YELLOW_BG: StyleStr
466
+ BLUE_BG: StyleStr
467
+ MAGENTA_BG: StyleStr
468
+ CYAN_BG: StyleStr
469
+ WHITE_BG: StyleStr
470
+ ANSI_256_SET_BG: StyleStr
471
+ DEFAULT_BG_COLOR: StyleStr
472
+ FRAMED: StyleStr
473
+ ENCIRCLED: StyleStr
474
+ OVERLINED: StyleStr
475
+ NOT_FRAMED_OR_CIRCLED: StyleStr
476
+ IDEOGRAM_UNDER_OR_RIGHT: StyleStr
477
+ IDEOGRAM_2UNDER_OR_2RIGHT: StyleStr
478
+ IDEOGRAM_OVER_OR_LEFT: StyleStr
479
+ IDEOGRAM_2OVER_OR_2LEFT: StyleStr
480
+ CANCEL: StyleStr
481
+ BLACK_BRIGHT_FG: StyleStr
482
+ RED_BRIGHT_FG: StyleStr
483
+ GREEN_BRIGHT_FG: StyleStr
484
+ YELLOW_BRIGHT_FG: StyleStr
485
+ BLUE_BRIGHT_FG: StyleStr
486
+ MAGENTA_BRIGHT_FG: StyleStr
487
+ CYAN_BRIGHT_FG: StyleStr
488
+ WHITE_BRIGHT_FG: StyleStr
489
+ BLACK_BRIGHT_BG: StyleStr
490
+ RED_BRIGHT_BG: StyleStr
491
+ GREEN_BRIGHT_BG: StyleStr
492
+ YELLOW_BRIGHT_BG: StyleStr
493
+ BLUE_BRIGHT_BG: StyleStr
494
+ MAGENTA_BRIGHT_BG: StyleStr
495
+ CYAN_BRIGHT_BG: StyleStr
496
+ WHITE_BRIGHT_BG: StyleStr
497
+
498
+
499
+ def _bg_wrapper_factory(__x: Color):
500
+ return color_str_wrapper(bg=__x, ansi_type='24b')
501
+
502
+
503
+ def _fg_wrapper_factory(__x: Color):
504
+ return color_str_wrapper(fg=__x, ansi_type='24b')
505
+
506
+
507
+ class AnsiBack(ColorNamespace[color_str_wrapper], factory=_bg_wrapper_factory):
508
+ RESET = getattr(AnsiStyle(), 'DEFAULT_BG_COLOR')
509
+
510
+ def __call__(self, bg: Union[Color, int, tuple[int, int, int]]):
511
+ return color_str_wrapper(bg=bg)
512
+
513
+
514
+ class AnsiFore(ColorNamespace[color_str_wrapper], factory=_fg_wrapper_factory):
515
+ RESET = getattr(AnsiStyle(), 'DEFAULT_FG_COLOR')
516
+
517
+ def __call__(self, fg: Union[Color, int, tuple[int, int, int]]):
518
+ return color_str_wrapper(fg=fg)
519
+
520
+
521
+ class _color_ns_getter:
522
+ mapping = MappingProxyType(
523
+ {k.casefold(): v.rgb
524
+ for (k, v) in
525
+ ColorNamespace().as_dict().items()})
526
+
527
+ def __get__(self, instance, owner: type = None):
528
+ if instance:
529
+ return self
530
+ dummy = type.__new__(type, (cls_name := type(self).__name__), (), {})
531
+ dummy_str = f"<attr {cls_name!r} of {owner.__name__!r} objects>"
532
+ dummy.__str__ = lambda _: dummy_str
533
+ return dummy()
534
+
535
+ @staticmethod
536
+ @lru_cache
537
+ def _normalize_key(__key: str):
538
+ return __key.translate({0x20: 0x5f}).casefold()
539
+
540
+ def __contains__(self, __key):
541
+ if type(__key) is str:
542
+ return self._normalize_key(__key) in self.mapping
543
+ return False
544
+
545
+ def __getitem__(self, __key: str):
546
+ return self.mapping[self._normalize_key(__key)]
547
+
548
+ def __getattr__(self, __name):
549
+ try:
550
+ return getattr(self.mapping, __name)
551
+ except AttributeError as e:
552
+ raise AttributeError(
553
+ str(e).replace(
554
+ *map(
555
+ lambda x: type(x).__name__,
556
+ (self.mapping, self)))
557
+ ) from None
558
+
559
+
560
+ def _handle_singleton(__obj: ...):
561
+ return (__obj,) if isinstance(__obj, (str, int)) else __obj
562
+
563
+
564
+ def _scalar_union(s: set, value: object):
565
+ return s.union(_handle_singleton(value))
566
+
567
+
568
+ # noinspection PyUnresolvedReferences
569
+ class rgb_dispatch[** P, R]:
570
+ color_ns = cast(
571
+ MappingProxyType[str, Int3Tuple],
572
+ _color_ns_getter())
573
+
574
+ def __new__(cls, func: Callable[P, R] = None, /, *, args: Sequence[str | int] = ()):
575
+ args = _handle_singleton(args)
576
+ if func is None:
577
+ return lambda f, **kwargs: (
578
+ cls(f, args=tuple(_scalar_union(set(args), kwargs.get('args', ()))))
579
+ )
580
+ inst = super().__new__(cls)
581
+ setattr(inst, 'func', func)
582
+ getattr(inst, '_init_wrapper')(*args)
583
+ return inst
584
+
585
+ def _init_wrapper(
586
+ self,
587
+ *params: *tuple[str | int, ...]
588
+ ):
589
+ if not callable(self.func):
590
+ raise ValueError
591
+ try:
592
+ argspec = getfullargspec(self.func)
593
+ sig = signature(self.func)
594
+ except TypeError:
595
+ if not (getattr(self.func, '__module__', '') == 'builtins'
596
+ or inspect.isbuiltin(self.func)):
597
+ raise
598
+ generic_spec = lambda *args, **kwargs: ...
599
+ argspec = getfullargspec(generic_spec)
600
+ sig = signature(generic_spec)
601
+ self.variadic = {argspec.varargs, argspec.varkw}
602
+ self.variadic.discard(None)
603
+ all_args = self.variadic.union(argspec.args + argspec.kwonlyargs)
604
+ self.rgb_args = all_args & {
605
+ *params,
606
+ *(v for (s, v) in zip(
607
+ ('*' * x for x in range(1, 3)),
608
+ (argspec.varargs, argspec.varkw))
609
+ if s in params)
610
+ }
611
+ if not self.rgb_args:
612
+ keys = frozenset({'fg', 'bg'})
613
+ for arg in all_args:
614
+ if (arg[:2] in keys) or (arg[-2:] in keys):
615
+ self.rgb_args.add(arg)
616
+ self.variadic &= self.rgb_args
617
+ self.signature = sig.replace(
618
+ parameters=[
619
+ param.replace(
620
+ annotation=' | '.join(
621
+ {'str'}.union(filter(None, f"{param.annotation}".split(' | ')))))
622
+ if name in self.rgb_args and param.annotation is not param.empty
623
+ else param
624
+ for (name, param) in sig.parameters.items()
625
+ ])
626
+ update_wrapper(self, self.func)
627
+
628
+ def __call__(
629
+ self,
630
+ *args: P.args,
631
+ **kwargs: P.kwargs
632
+ ) -> R:
633
+ bound = self.signature.bind(*args, **kwargs)
634
+ bound.apply_defaults()
635
+ for arg, value in bound.arguments.items():
636
+ if arg not in self.rgb_args:
637
+ continue
638
+ if arg in self.variadic:
639
+ bound.arguments[arg] = (
640
+ tuple(
641
+ self.color_ns[v] if v in self.color_ns else v
642
+ for v in value)
643
+ if isinstance(value, tuple) else
644
+ {k: self.color_ns[v] if v in self.color_ns else v
645
+ for k, v in value.items()}
646
+ )
647
+ elif value in self.color_ns:
648
+ bound.arguments[arg] = self.color_ns[value]
649
+ return self.func(*bound.args, **bound.kwargs)
650
+
651
+
652
+ def display_named_colors():
653
+ return [ColorStr(name.replace('_', ' ').lower(), color_spec=color, ansi_type='24b')
654
+ for name, color in ColorNamespace().as_dict().items()]
655
+
656
+
657
+ def display_ansi256_color_range():
658
+ from numpy import asarray
659
+ from chromatic.color.colorconv import ansi_8bit_to_rgb
660
+
661
+ ansi256_range = asarray(range(256)).reshape([16] * 2).tolist()
662
+ return [[ColorStr(
663
+ obj='###',
664
+ color_spec=ansi_8bit_to_rgb(v),
665
+ ansi_type='8b')
666
+ for v in arr]
667
+ for arr in ansi256_range]
668
+
669
+
670
+ def __getattr__(name: ...) -> ...:
671
+ if name == 'Back':
672
+ return AnsiBack()
673
+ if name == 'Fore':
674
+ return AnsiFore()
675
+ if name == 'Style':
676
+ return AnsiStyle()
677
+ raise AttributeError(
678
+ f"Module {__name__!r} has no attribute {name!r}")
679
+
680
+
681
+ if TYPE_CHECKING:
682
+ Back: AnsiBack
683
+ Fore: AnsiFore
684
+ Style: AnsiStyle
685
+
686
+ __all__ = [
687
+ 'Back',
688
+ 'ColorNamespace',
689
+ 'Fore',
690
+ 'Style',
691
+ 'color_str_wrapper',
692
+ 'rgb_dispatch',
693
+ ]