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,330 @@
1
+ __all__ = [
2
+ 'Back',
3
+ 'ColorNamespace',
4
+ 'Fore',
5
+ 'Style',
6
+ 'color_str_wrapper',
7
+ ]
8
+
9
+ from collections.abc import Sequence
10
+ from types import MappingProxyType
11
+ from typing import Callable, Iterator, overload, TypedDict, Union, Unpack
12
+
13
+ from chromatic._typing import AnsiColorAlias, Int3Tuple
14
+ from chromatic.color.core import AnsiColorFormat, Color, ColorStr, SgrParameter, SgrSequence
15
+
16
+ type _ColorLike = Union[Color, int, tuple[int, int, int]]
17
+
18
+
19
+ def display_ansi256_color_range() -> list[list[ColorStr]]: ...
20
+
21
+
22
+ def display_named_colors() -> list[ColorStr]: ...
23
+
24
+
25
+ class AnsiBack(ColorNamespace[color_str_wrapper]):
26
+ RESET: color_str_wrapper
27
+
28
+ def __call__(self, bg: _ColorLike) -> color_str_wrapper: ...
29
+
30
+
31
+ class AnsiFore(ColorNamespace[color_str_wrapper]):
32
+ RESET: color_str_wrapper
33
+
34
+ def __call__(self, fg: _ColorLike) -> color_str_wrapper: ...
35
+
36
+
37
+ class AnsiStyle[StyleStr: color_str_wrapper](DynamicNamespace[StyleStr]):
38
+ RESET: StyleStr
39
+ BOLD: StyleStr
40
+ FAINT: StyleStr
41
+ ITALICS: StyleStr
42
+ SINGLE_UNDERLINE: StyleStr
43
+ SLOW_BLINK: StyleStr
44
+ RAPID_BLINK: StyleStr
45
+ NEGATIVE: StyleStr
46
+ CONCEALED_CHARS: StyleStr
47
+ CROSSED_OUT: StyleStr
48
+ PRIMARY: StyleStr
49
+ FIRST_ALT: StyleStr
50
+ SECOND_ALT: StyleStr
51
+ THIRD_ALT: StyleStr
52
+ FOURTH_ALT: StyleStr
53
+ FIFTH_ALT: StyleStr
54
+ SIXTH_ALT: StyleStr
55
+ SEVENTH_ALT: StyleStr
56
+ EIGHTH_ALT: StyleStr
57
+ NINTH_ALT: StyleStr
58
+ GOTHIC: StyleStr
59
+ DOUBLE_UNDERLINE: StyleStr
60
+ RESET_BOLD_AND_FAINT: StyleStr
61
+ RESET_ITALIC_AND_GOTHIC: StyleStr
62
+ RESET_UNDERLINES: StyleStr
63
+ RESET_BLINKING: StyleStr
64
+ POSITIVE: StyleStr
65
+ REVEALED_CHARS: StyleStr
66
+ RESET_CROSSED_OUT: StyleStr
67
+ BLACK_FG: StyleStr
68
+ RED_FG: StyleStr
69
+ GREEN_FG: StyleStr
70
+ YELLOW_FG: StyleStr
71
+ BLUE_FG: StyleStr
72
+ MAGENTA_FG: StyleStr
73
+ CYAN_FG: StyleStr
74
+ WHITE_FG: StyleStr
75
+ ANSI_256_SET_FG: StyleStr
76
+ DEFAULT_FG_COLOR: StyleStr
77
+ BLACK_BG: StyleStr
78
+ RED_BG: StyleStr
79
+ GREEN_BG: StyleStr
80
+ YELLOW_BG: StyleStr
81
+ BLUE_BG: StyleStr
82
+ MAGENTA_BG: StyleStr
83
+ CYAN_BG: StyleStr
84
+ WHITE_BG: StyleStr
85
+ ANSI_256_SET_BG: StyleStr
86
+ DEFAULT_BG_COLOR: StyleStr
87
+ FRAMED: StyleStr
88
+ ENCIRCLED: StyleStr
89
+ OVERLINED: StyleStr
90
+ NOT_FRAMED_OR_CIRCLED: StyleStr
91
+ IDEOGRAM_UNDER_OR_RIGHT: StyleStr
92
+ IDEOGRAM_2UNDER_OR_2RIGHT: StyleStr
93
+ IDEOGRAM_OVER_OR_LEFT: StyleStr
94
+ IDEOGRAM_2OVER_OR_2LEFT: StyleStr
95
+ CANCEL: StyleStr
96
+ BLACK_BRIGHT_FG: StyleStr
97
+ RED_BRIGHT_FG: StyleStr
98
+ GREEN_BRIGHT_FG: StyleStr
99
+ YELLOW_BRIGHT_FG: StyleStr
100
+ BLUE_BRIGHT_FG: StyleStr
101
+ MAGENTA_BRIGHT_FG: StyleStr
102
+ CYAN_BRIGHT_FG: StyleStr
103
+ WHITE_BRIGHT_FG: StyleStr
104
+ BLACK_BRIGHT_BG: StyleStr
105
+ RED_BRIGHT_BG: StyleStr
106
+ GREEN_BRIGHT_BG: StyleStr
107
+ YELLOW_BRIGHT_BG: StyleStr
108
+ BLUE_BRIGHT_BG: StyleStr
109
+ MAGENTA_BRIGHT_BG: StyleStr
110
+ CYAN_BRIGHT_BG: StyleStr
111
+ WHITE_BRIGHT_BG: StyleStr
112
+
113
+
114
+ class color_str_wrapper:
115
+
116
+ def __add__(self, other) -> ColorStr: ...
117
+
118
+ def __call__(self, __obj=None) -> color_str_wrapper | ColorStr: ...
119
+
120
+ def __init__(self, **kwargs: Unpack[_ColorStrWrapperKwargs]) -> None: ...
121
+
122
+ def __repr__(self) -> str: ...
123
+
124
+ def __str__(self) -> str: ...
125
+
126
+ _ansi_type_: type[AnsiColorFormat]
127
+ _sgr_: SgrSequence
128
+
129
+
130
+ class DynamicNamespace[_VT](metaclass=DynamicNSMeta[_VT]):
131
+
132
+ def as_dict(self) -> dict[str, _VT]: ...
133
+
134
+ def __init__[_KT](self, **kwargs: dict[_KT, _VT]) -> None: ...
135
+
136
+ def __init_subclass__(cls, **kwargs) -> DynamicNamespace[_VT]: ...
137
+
138
+ def __iter__(self) -> Iterator[_VT]: ...
139
+
140
+ def __new__(cls, *args, **kwargs) -> DynamicNamespace[_VT]: ...
141
+
142
+ def __setattr__(self, name, value) -> None: ...
143
+
144
+ __members__: list[_VT]
145
+
146
+
147
+ class DynamicNSMeta[_VT](type):
148
+
149
+ def __new__(
150
+ mcls,
151
+ clsname: str,
152
+ bases: tuple[type, ...],
153
+ mapping: dict[str, ...],
154
+ **kwargs
155
+ ) -> DynamicNSMeta[_VT]: ...
156
+
157
+
158
+ class ColorNamespace[NamedColor: Color](DynamicNamespace[NamedColor]):
159
+ BLACK: NamedColor
160
+ DIM_GREY: NamedColor
161
+ GREY: NamedColor
162
+ DARK_GREY: NamedColor
163
+ SILVER: NamedColor
164
+ LIGHT_GREY: NamedColor
165
+ WHITE_SMOKE: NamedColor
166
+ WHITE: NamedColor
167
+ ROSY_BROWN: NamedColor
168
+ INDIAN_RED: NamedColor
169
+ BROWN: NamedColor
170
+ FIREBRICK: NamedColor
171
+ LIGHT_CORAL: NamedColor
172
+ MAROON: NamedColor
173
+ DARK_RED: NamedColor
174
+ RED: NamedColor
175
+ SNOW: NamedColor
176
+ MISTY_ROSE: NamedColor
177
+ SALMON: NamedColor
178
+ TOMATO: NamedColor
179
+ BURNT_SIENNA: NamedColor
180
+ DARK_SALMON: NamedColor
181
+ CORAL: NamedColor
182
+ ORANGE_RED: NamedColor
183
+ LIGHT_SALMON: NamedColor
184
+ SIENNA: NamedColor
185
+ SEASHELL: NamedColor
186
+ CHOCOLATE: NamedColor
187
+ SADDLE_BROWN: NamedColor
188
+ SANDY_BROWN: NamedColor
189
+ PEACH_PUFF: NamedColor
190
+ PERU: NamedColor
191
+ LINEN: NamedColor
192
+ BISQUE: NamedColor
193
+ DARK_ORANGE: NamedColor
194
+ BURLY_WOOD: NamedColor
195
+ ANTIQUE_WHITE: NamedColor
196
+ TAN: NamedColor
197
+ NAVAJO_WHITE: NamedColor
198
+ BLANCHED_ALMOND: NamedColor
199
+ PAPAYA_WHIP: NamedColor
200
+ MOCCASIN: NamedColor
201
+ ORANGE: NamedColor
202
+ WHEAT: NamedColor
203
+ OLD_LACE: NamedColor
204
+ FLORAL_WHITE: NamedColor
205
+ DARK_GOLDENROD: NamedColor
206
+ GOLDENROD: NamedColor
207
+ CORNSILK: NamedColor
208
+ GOLD: NamedColor
209
+ LEMON_CHIFFON: NamedColor
210
+ KHAKI: NamedColor
211
+ PALE_GOLDENROD: NamedColor
212
+ DARK_KHAKI: NamedColor
213
+ BEIGE: NamedColor
214
+ LIGHT_GOLDENROD_YELLOW: NamedColor
215
+ OLIVE: NamedColor
216
+ YELLOW: NamedColor
217
+ LIGHT_YELLOW: NamedColor
218
+ IVORY: NamedColor
219
+ OLIVE_DRAB: NamedColor
220
+ YELLOW_GREEN: NamedColor
221
+ DARK_OLIVE_GREEN: NamedColor
222
+ GREEN_YELLOW: NamedColor
223
+ CHARTREUSE: NamedColor
224
+ LAWN_GREEN: NamedColor
225
+ DARK_SEA_GREEN: NamedColor
226
+ FOREST_GREEN: NamedColor
227
+ LIME_GREEN: NamedColor
228
+ LIGHT_GREEN: NamedColor
229
+ PALE_GREEN: NamedColor
230
+ DARK_GREEN: NamedColor
231
+ GREEN: NamedColor
232
+ LIME: NamedColor
233
+ HONEYDEW: NamedColor
234
+ SEA_GREEN: NamedColor
235
+ MEDIUM_SEA_GREEN: NamedColor
236
+ SPRING_GREEN: NamedColor
237
+ MINT_CREAM: NamedColor
238
+ MEDIUM_SPRING_GREEN: NamedColor
239
+ MEDIUM_AQUAMARINE: NamedColor
240
+ AQUAMARINE: NamedColor
241
+ TURQUOISE: NamedColor
242
+ LIGHT_SEA_GREEN: NamedColor
243
+ MEDIUM_TURQUOISE: NamedColor
244
+ DARK_SLATE_GREY: NamedColor
245
+ PALE_TURQUOISE: NamedColor
246
+ TEAL: NamedColor
247
+ DARK_CYAN: NamedColor
248
+ CYAN: NamedColor
249
+ LIGHT_CYAN: NamedColor
250
+ AZURE: NamedColor
251
+ DARK_TURQUOISE: NamedColor
252
+ CADET_BLUE: NamedColor
253
+ POWDER_BLUE: NamedColor
254
+ LIGHT_BLUE: NamedColor
255
+ DEEP_SKY_BLUE: NamedColor
256
+ SKY_BLUE: NamedColor
257
+ LIGHT_SKY_BLUE: NamedColor
258
+ STEEL_BLUE: NamedColor
259
+ ALICE_BLUE: NamedColor
260
+ DODGER_BLUE: NamedColor
261
+ SLATE_GREY: NamedColor
262
+ LIGHT_SLATE_GREY: NamedColor
263
+ LIGHT_STEEL_BLUE: NamedColor
264
+ CORNFLOWER_BLUE: NamedColor
265
+ ROYAL_BLUE: NamedColor
266
+ MIDNIGHT_BLUE: NamedColor
267
+ LAVENDER: NamedColor
268
+ NAVY: NamedColor
269
+ DARK_BLUE: NamedColor
270
+ MEDIUM_BLUE: NamedColor
271
+ BLUE: NamedColor
272
+ GHOST_WHITE: NamedColor
273
+ SLATE_BLUE: NamedColor
274
+ DARK_SLATE_BLUE: NamedColor
275
+ MEDIUM_SLATE_BLUE: NamedColor
276
+ MEDIUM_PURPLE: NamedColor
277
+ REBECCA_PURPLE: NamedColor
278
+ BLUE_VIOLET: NamedColor
279
+ INDIGO: NamedColor
280
+ DARK_ORCHID: NamedColor
281
+ DARK_VIOLET: NamedColor
282
+ MEDIUM_ORCHID: NamedColor
283
+ THISTLE: NamedColor
284
+ PLUM: NamedColor
285
+ VIOLET: NamedColor
286
+ PURPLE: NamedColor
287
+ DARK_MAGENTA: NamedColor
288
+ FUCHSIA: NamedColor
289
+ ORCHID: NamedColor
290
+ MEDIUM_VIOLET_RED: NamedColor
291
+ DEEP_PINK: NamedColor
292
+ HOT_PINK: NamedColor
293
+ LAVENDER_BLUSH: NamedColor
294
+ PALE_VIOLET_RED: NamedColor
295
+ CRIMSON: NamedColor
296
+ PINK: NamedColor
297
+ LIGHT_PINK: NamedColor
298
+
299
+
300
+ # noinspection PyTypedDict
301
+ class _ColorStrWrapperKwargs(TypedDict, total=False):
302
+ ansi_type: Union[AnsiColorAlias, type[AnsiColorFormat]]
303
+ bg: _ColorLike
304
+ fg: _ColorLike
305
+ sgr_params: Sequence[Union[int, SgrParameter]]
306
+
307
+
308
+ class rgb_dispatch[** P, R]:
309
+ color_ns: MappingProxyType[str, Int3Tuple]
310
+
311
+ @overload
312
+ def __new__(
313
+ cls,
314
+ func: Callable[P, R], /, *, args: Sequence[str] = ()
315
+ ):
316
+ return func
317
+
318
+ @overload
319
+ def __new__(
320
+ cls,
321
+ func: None = None, /, *, args: Sequence[str] = ()
322
+ ) -> type[rgb_dispatch]:
323
+ ...
324
+
325
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: ...
326
+
327
+
328
+ Back = AnsiBack()
329
+ Fore = AnsiFore()
330
+ Style = AnsiStyle()
@@ -0,0 +1,189 @@
1
+ import json
2
+ import os
3
+ from enum import IntEnum
4
+ from functools import partial
5
+ from hashlib import sha256
6
+ from pathlib import Path
7
+ from typing import Iterable, Literal, TYPE_CHECKING
8
+
9
+ from PIL import Image
10
+
11
+ if TYPE_CHECKING:
12
+ from _typeshed import SupportsWrite
13
+
14
+ data_root = Path(os.path.dirname(__file__))
15
+ stub = data_root / (__file__ + 'i')
16
+ config = data_root / 'config.json'
17
+ fonts = data_root / 'fonts'
18
+ images = data_root / 'images'
19
+
20
+
21
+ def _get_checksum(__fp_iter: Iterable[str]) -> str:
22
+ return sha256(';'.join(sorted(__fp_iter)).encode()).hexdigest()
23
+
24
+
25
+ def _is_img_ext(__fp: str):
26
+ return __fp.endswith(('.png', '.jpg', '.jpeg', '.webp'))
27
+
28
+
29
+ def _is_ttf_ext(__fp: str):
30
+ return __fp.endswith(('.ttf', '.ttc'))
31
+
32
+
33
+ def _build_config():
34
+ from string import printable
35
+
36
+ f: SupportsWrite
37
+ d: dict[Literal['fonts', 'images'] | Literal['__hash__'], dict[str, str] | str]
38
+ d = {
39
+ 'fonts': {},
40
+ 'images': {},
41
+ '__hash__': ''
42
+ }
43
+ printable = ''.join(c for c in printable if any((c.isalnum(), c.isidentifier(), c == '.')))
44
+ for font_fp in ((Path(fonts) / x).absolute() for x in
45
+ filter(_is_ttf_ext, os.listdir(fonts))):
46
+ font_name = font_fp.stem
47
+ for c in set(font_name):
48
+ if c not in printable:
49
+ font_name = font_name.replace(c, '_')
50
+ d['fonts'][font_name.upper()] = str(font_fp.relative_to(data_root))
51
+ for image_fp in ((Path(images) / x).absolute() for x in
52
+ filter(_is_img_ext, os.listdir(images))):
53
+ img_name = image_fp.stem
54
+ for c in set(img_name):
55
+ if c not in printable:
56
+ img_name = img_name.replace(c, '_')
57
+ d['images'][img_name.lower()] = str(image_fp.relative_to(data_root))
58
+ d['__hash__'] = _get_checksum((d['fonts'] | d['images']).values())
59
+ with config.open('w', encoding='utf-8') as f:
60
+ json.dump(d, f, indent='\t')
61
+ return d
62
+
63
+
64
+ def _validate(**kwargs):
65
+ need_new_stub = kwargs.get('update_stub', False)
66
+ if need_new_stub or not config.exists():
67
+ json_data = _build_config()
68
+ need_new_stub = True
69
+ else:
70
+ json_data = json.load(config.open('r'))
71
+ s1, s2 = (set(
72
+ str(fp.relative_to(data_root)) for fp in
73
+ ((Path(subdir) / x).absolute() for x in filter(f, os.listdir(subdir))))
74
+ for f, subdir in zip((_is_ttf_ext, _is_img_ext), (fonts, images)))
75
+ if json_data['__hash__'] != _get_checksum(s1 | s2):
76
+ json_data = _build_config()
77
+ need_new_stub = True
78
+ font_data, img_data = json_data['fonts'], json_data['images']
79
+ if need_new_stub or not stub.exists():
80
+ exports = ['register_user_font', 'UserFont']
81
+ img_funcdefs = []
82
+ for img_name in img_data.keys():
83
+ exports.append(img_name)
84
+ img_funcdefs.append(f"def {img_name}() -> ImageFile: ...")
85
+ body = [
86
+ f"__all__ = [{', '.join(map(repr, exports))}]",
87
+ 'from PIL.ImageFile import ImageFile',
88
+ 'from enum import IntEnum',
89
+ 'from os import PathLike',
90
+ 'from pathlib import Path',
91
+ 'def register_user_font[AnyStr: (str, bytes)]'
92
+ '(__path: AnyStr | PathLike[AnyStr]) -> None: ...',
93
+ ] + img_funcdefs
94
+ body.extend(
95
+ '\n\t'.join(
96
+ ('class UserFont(IntEnum):',
97
+ *(f'{x} = {i}' for i, x in enumerate(sorted(font_data))),
98
+ '@property',
99
+ 'def path(self) -> Path: ...')).replace('\t', ' ' * 4).splitlines())
100
+ stub.open('w', encoding='utf-8').write('\n'.join(body))
101
+ return font_data, img_data
102
+
103
+
104
+ _font_data_, _img_data_ = _validate()
105
+
106
+
107
+ def _create_font_enum() -> type['UserFont']:
108
+ def path(self):
109
+ return data_root / Path(_font_data_[self.name])
110
+
111
+ enum_cls = IntEnum(
112
+ 'UserFont',
113
+ {k: i for (i, k) in enumerate(sorted(_font_data_.keys()))})
114
+ enum_cls.path = property(path)
115
+ return enum_cls
116
+
117
+
118
+ UserFont = _create_font_enum()
119
+
120
+ def register_user_font[AnyStr: (str, bytes)](
121
+ __path: AnyStr | os.PathLike[AnyStr]
122
+ ):
123
+ """Register a .ttf font file as a new :class:`UserFont` enum member.
124
+
125
+ If the source file is on the same drive :mod:`chromatic.data`,
126
+ a symlink to it is added to the ``data/fonts`` package subdirectory.
127
+
128
+ Parameters
129
+ ----------
130
+ __path : AnyStr | PathLike[AnyStr]
131
+ Path to the .ttf font file being registered.
132
+
133
+ Raises
134
+ ------
135
+ FileNotFoundError
136
+ If the specified path does not exist.
137
+ ValueError
138
+ If the file is not a .ttf font.
139
+ OSError
140
+ If the font file is invalid or cannot be loaded.
141
+ """
142
+ path = os.fspath(__path)
143
+ if not os.path.exists(path):
144
+ raise FileNotFoundError(
145
+ f"{__path!r}")
146
+ path_obj = Path(path)
147
+ if path_obj.is_symlink():
148
+ path_obj = path_obj.readlink()
149
+ if path_obj.suffix != '.ttf':
150
+ raise ValueError(
151
+ f"Expected '.ttf' file, "
152
+ f"got filetype {path_obj.suffix!r} instead")
153
+ from PIL.ImageFont import FreeTypeFont
154
+
155
+ try:
156
+ _ = FreeTypeFont(path_obj)
157
+ except OSError as err:
158
+ if path_obj.exists():
159
+ err.add_note(f"{path_obj.resolve()!r}")
160
+ raise err
161
+ src = path_obj.absolute().relative_to(data_root)
162
+ src_pardir = src.parent if not src.is_dir() else src
163
+ if fonts.samefile(src_pardir):
164
+ is_link = False
165
+ else:
166
+ is_link = src.drive == fonts.drive
167
+ path_obj = Path(fonts / (src.stem + ('.ttf' if not is_link else '.lnk')))
168
+ ttf_obj = FreeTypeFont(path_obj)
169
+ ttf_name = ttf_obj.getname()
170
+ if any(ttf_name == FreeTypeFont(v.path).getname() for v in UserFont):
171
+ return print(f"{ttf_name} is already a UserFont member")
172
+ if is_link:
173
+ if path_obj.exists():
174
+ path_obj.unlink()
175
+ path_obj.symlink_to(src)
176
+ else:
177
+ path_obj.write_bytes(src.read_bytes())
178
+ return print(f"Successfully registered new UserFont: {ttf_name}")
179
+
180
+ def __getattr__(name) -> ...:
181
+ if name.startswith('_'):
182
+ pass
183
+ elif name in _img_data_:
184
+ return partial(Image.open, fp=data_root / Path(_img_data_[name]))
185
+ raise AttributeError(
186
+ f"Module '{__name__}' has no attribute '{name}'")
187
+
188
+
189
+ __all__ = ['UserFont', *_img_data_, 'register_user_font']
@@ -0,0 +1,15 @@
1
+ __all__ = ['register_user_font', 'UserFont', 'butterfly', 'escher', 'goblin_virus', 'hotdog']
2
+ from PIL.ImageFile import ImageFile
3
+ from enum import IntEnum
4
+ from os import PathLike
5
+ from pathlib import Path
6
+ def register_user_font[AnyStr: (str, bytes)](__path: AnyStr | PathLike[AnyStr]) -> None: ...
7
+ def butterfly() -> ImageFile: ...
8
+ def escher() -> ImageFile: ...
9
+ def goblin_virus() -> ImageFile: ...
10
+ def hotdog() -> ImageFile: ...
11
+ class UserFont(IntEnum):
12
+ CONSOLAS = 0
13
+ IBM_VGA_437_8X16 = 1
14
+ @property
15
+ def path(self) -> Path: ...
Binary file
Binary file
Binary file
Binary file
Binary file