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.
chromatic/__init__.py ADDED
@@ -0,0 +1,26 @@
1
+ from . import ascii, color, data
2
+ from .ascii import (
3
+ ansi2img,
4
+ ansi_quantize,
5
+ ascii2img,
6
+ ascii_printable,
7
+ contrast_stretch,
8
+ cp437_printable,
9
+ equalize_white_point,
10
+ get_font_key,
11
+ get_font_object,
12
+ img2ansi,
13
+ img2ascii,
14
+ read_ans,
15
+ render_ans,
16
+ reshape_ansi,
17
+ to_sgr_array
18
+ )
19
+ from .ascii._glyph_proc import get_glyph_masks
20
+ from .color import (
21
+ ansicolor24Bit, ansicolor4Bit, ansicolor8Bit, Back, Color, colorbytes, ColorStr, Fore,
22
+ SgrParameter, Style
23
+ )
24
+ from .data import register_user_font
25
+
26
+ __all__ = []
chromatic/_typing.py ADDED
@@ -0,0 +1,168 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from functools import reduce
5
+ from numbers import Number
6
+ from types import UnionType
7
+ from typing import (
8
+ Any, Callable, Concatenate, get_args, get_origin, get_type_hints, Iterable, Literal, ParamSpec,
9
+ Protocol, Sequence, SupportsRound, TYPE_CHECKING, TypeVar, Union
10
+ )
11
+
12
+ from numpy import dtype, float64, generic, ndarray, number, uint8
13
+ from numpy._typing import _ArrayLike, NDArray
14
+ from PIL.Image import Image
15
+ from PIL.ImageFont import FreeTypeFont
16
+
17
+ from chromatic.data import UserFont
18
+
19
+ _P = ParamSpec('_P')
20
+ _T = TypeVar('_T')
21
+ _T_co = TypeVar('_T_co', covariant=True)
22
+ _T_contra = TypeVar('_T_contra', contravariant=True)
23
+ _AnyNumber_co = TypeVar('_AnyNumber_co', number, Number, covariant=True)
24
+
25
+ if TYPE_CHECKING:
26
+ from _typeshed import SupportsRichComparison, SupportsDivMod
27
+
28
+
29
+ class SupportsRoundAndDivMod(
30
+ SupportsRound[_T_co],
31
+ SupportsDivMod[Any, _T_co],
32
+ Protocol
33
+ ):
34
+ ...
35
+
36
+ type ArrayReducerFunc[_SCT: generic] = Callable[Concatenate[_ArrayLike[_SCT], _P], NDArray[_SCT]]
37
+ type KeyFunction[_T] = Callable[[_T], SupportsRichComparison]
38
+ type ShapedNDArray[_Shape: tuple[int, ...], _SCT: generic] = ndarray[_Shape, dtype[_SCT]]
39
+ type MatrixLike[_SCT: generic] = ShapedNDArray[TupleOf2[int], _SCT]
40
+ type SquareMatrix[_I: int, _SCT: generic] = ShapedNDArray[TupleOf2[_I], _SCT]
41
+ type GlyphArray[_SCT: generic] = SquareMatrix[Literal[24], _SCT]
42
+ type TupleOf2[_T] = tuple[_T, _T]
43
+ type TupleOf3[_T] = tuple[_T, _T, _T]
44
+ Float3Tuple = TupleOf3[float]
45
+ Int3Tuple = TupleOf3[int]
46
+ FloatSequence = Sequence[float]
47
+ IntSequence = Sequence[int]
48
+ GlyphBitmask = GlyphArray[bool]
49
+ Bitmask = MatrixLike[bool]
50
+ GreyscaleGlyphArray = GlyphArray[float64]
51
+ GreyscaleArray = MatrixLike[float64]
52
+ RGBArray = ShapedNDArray[tuple[int, int, Literal[3]], uint8]
53
+ RGBPixel = ShapedNDArray[tuple[Literal[3]], uint8]
54
+
55
+ RGBImageLike = Union[Image, RGBArray]
56
+ RGBVectorLike = Union[Int3Tuple, IntSequence, RGBPixel]
57
+ ColorDictKeys = Literal['fg', 'bg']
58
+ Ansi4BitAlias = Literal['4b']
59
+ Ansi8BitAlias = Literal['8b']
60
+ Ansi24BitAlias = Literal['24b']
61
+ AnsiColorAlias = Ansi4BitAlias | Ansi8BitAlias | Ansi24BitAlias
62
+ FontArgType = Union[FreeTypeFont | UserFont, str, int]
63
+
64
+
65
+ def is_matching_type(value, typ):
66
+ if typ is Any:
67
+ return True
68
+ origin, args = deconstruct_type(typ)
69
+ if origin is Union:
70
+ return any(is_matching_type(value, arg) for arg in args)
71
+ elif origin is Literal:
72
+ return value in args
73
+ elif isinstance(typ, TypeVar):
74
+ if typ.__constraints__:
75
+ return any(
76
+ is_matching_type(value, constraint) for constraint in typ.__constraints__)
77
+ else:
78
+ return True
79
+ elif origin is type:
80
+ if not isinstance(value, type):
81
+ return False
82
+ target_type = args[0]
83
+ target_origin = get_origin(target_type)
84
+ target_args = get_args(target_type)
85
+ if target_origin is Union:
86
+ return any(issubclass(value, t) for t in target_args)
87
+ else:
88
+ return issubclass(value, target_type)
89
+ elif origin is Callable:
90
+ return is_matching_callable(value, typ)
91
+ elif origin is list:
92
+ if not isinstance(value, list):
93
+ return False
94
+ if not args:
95
+ return True
96
+ return all(is_matching_type(item, args[0]) for item in value)
97
+ elif origin is dict:
98
+ if not isinstance(value, dict):
99
+ return False
100
+ if not args:
101
+ return True
102
+ key_type, val_type = args
103
+ return all(
104
+ is_matching_type(k, key_type) and is_matching_type(v, val_type) for k, v in
105
+ value.items())
106
+ elif origin is tuple:
107
+ if not isinstance(value, tuple):
108
+ return False
109
+ if len(args) == 2 and args[1] is ...:
110
+ return all(is_matching_type(item, args[0]) for item in value)
111
+ if len(value) != len(args):
112
+ return False
113
+ return all(is_matching_type(v, t) for v, t in zip(value, args))
114
+ else:
115
+ try:
116
+ return isinstance(value, typ)
117
+ except TypeError:
118
+ return False
119
+
120
+
121
+ def deconstruct_type(tp):
122
+ origin = get_origin(tp) or tp
123
+ args = get_args(tp)
124
+ return origin, args
125
+
126
+
127
+ def is_matching_callable(value, expected_type):
128
+ if not callable(value):
129
+ return False
130
+ return id(value) == id(expected_type)
131
+
132
+
133
+ def pseudo_union(ts: Iterable[type]) -> Union[type, UnionType]:
134
+ return reduce(lambda x, y: x | y, ts)
135
+
136
+
137
+ def type_error_msg(err_obj, *expected, context: str = '', obj_repr=False):
138
+ n_expected = len(expected)
139
+ name_slots = [f"{{{n}.__qualname__!r}}" for n in range(n_expected)]
140
+ if name_slots and n_expected > 1:
141
+ name_slots[-1] = f"or {name_slots[-1]}"
142
+ names = (', ' if n_expected > 2 else ' ').join(
143
+ [context.strip()] + name_slots).format(*expected)
144
+ if not obj_repr:
145
+ if not isinstance(err_obj, type):
146
+ err_obj = type(err_obj)
147
+ oops = repr(err_obj.__qualname__)
148
+ elif not isinstance(err_obj, str):
149
+ oops = repr(err_obj)
150
+ else:
151
+ oops = err_obj
152
+ return f"expected {names}, got {oops} instead"
153
+
154
+
155
+ def is_matching_typed_dict(__d: dict, typed_dict: type[dict]) -> tuple[bool, str]:
156
+ if not isinstance(__d, dict):
157
+ return False, type_error_msg(__d, dict)
158
+ expected = get_type_hints(typed_dict)
159
+ if unexpected := __d.keys() - expected:
160
+ return False, f"unexpected keyword arguments: {unexpected}"
161
+ if missing := set(getattr(typed_dict, '__required_keys__', expected)) - __d.keys():
162
+ return False, f"missing required keys: {missing}"
163
+ for name, typ in expected.items():
164
+ if ((field := __d.get(name)) is not None) and not is_matching_type(field, typ):
165
+ return False, type_error_msg(
166
+ field, typ,
167
+ context=f'keyword argument {name!r} of type')
168
+ return True, ''
@@ -0,0 +1,5 @@
1
+ from ._array import *
2
+ from ._curses import *
3
+ from ._glyph_proc import *
4
+
5
+ __all__ = list(set(_array.__all__) | set(_curses.__all__) | set(_glyph_proc.__all__))