Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""
3Small utilities that simplify common tasks.
4"""
6from typing import Collection
7from typing import Generator
8from typing import Iterable
9from typing import Optional
10from typing import Sequence
13def assure_str(supposed_str) -> str:
14 if not isinstance(supposed_str, str):
15 raise TypeError(f"supposed_str ({supposed_str}) must be a str")
16 return supposed_str
19def assure_str_or_none(supposed_str) -> Optional[str]:
20 if not isinstance(supposed_str, str) and supposed_str is not None:
21 raise TypeError(f"supposed_str ({supposed_str}) must be a str")
22 return supposed_str
25def seq_get(seq: Sequence, defaults: Sequence, index: int):
26 """Get an element from a sequence by index. If the index is out of bounds,
27 get it from the default sequence.
29 Examples:
31 >>> seq_get([1, 2], [5, 6, 7, 8], 2)
32 7
33 >>> seq_get([1, 2], [5, 6, 7, 8], -1)
34 8
35 >>> seq_get([1, 2], [5, 6], -1)
36 2
37 """
38 if index < 0:
39 length = len(defaults)
40 index = length + index
41 if index < 0:
42 raise IndexError(
43 "sequence index out of range in both seq and defaults"
44 )
45 try:
46 return seq[index]
47 except IndexError:
48 try:
49 return defaults[index]
50 except IndexError as e:
51 raise IndexError(
52 "sequence index out of range in both seq and defaults"
53 ) from e
56def rgb888_to_rgb565(rgb_tuple: Collection[int]) -> int:
57 """Return a rgb595 int of an RGB888 color"""
58 red, green, blue = rgb_tuple
59 return (
60 (int(red / 255 * 31) << 11)
61 | (int(green / 255 * 63) << 5)
62 | (int(blue / 255 * 31))
63 )
66def bytes_to_int(input_bytes: Iterable) -> int:
67 """Concatenate a tuple of bytes or ints representing them into a single int.
69 For example (hex for easier understanding):
71 >>> hex(bytes_to_int((0xab, 0xcd, 0xef)))
72 >>> '0xabcdef'
73 """
74 result = 0
75 for byte in input_bytes:
76 result <<= 8
77 result |= byte
79 return result
82def sublists_from_iterable(
83 iterable: Iterable, length: int, yield_last_incomplete: bool = True
84) -> Generator:
85 """Yields lists of a certain length from an iterable.
87 This generator yields lists of length `length` from an interable
88 `iterable`.
90 Args:
91 iterable: from which this generator yields lists of elements
92 length: length of lists yielded
93 yield_last_incomplete: if :pycode`True`, yield the last sublist even if
94 it's shorter than `length`; if :pycode:`False`, raise a ValueError
95 if the last sublist is shorter than `length`
97 Yields:
98 `list`\\ s of elements yielded from `iterable`
100 Examples:
101 >>> from csnake.utils import sublists_from_iterable
102 >>> incomplete_ok = sublists_from_iterable(range(5), 4, True)
103 >>> print(list(incomplete_ok))
104 [[0, 1, 2, 3], [4]]
105 >>> incomplete_notok = sublists_from_iterable(range(5), 4, False)
106 >>> print(list(incomplete_notok))
107 ValueError: Input iterable's length is not divisible by sublist length
108 """
109 currentlist = []
110 index = 0
112 for item in iterable:
113 currentlist.append(item)
114 index += 1
115 if index == length:
116 yield currentlist
117 currentlist = []
118 index = 0
119 if currentlist:
120 if yield_last_incomplete:
121 yield currentlist
122 else:
123 raise ValueError(
124 "Input iterable's length is not divisible by sublist length"
125 )