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"""
5from typing import Collection
6from typing import Generator
7from typing import Iterable
8from typing import Optional
9from typing import Sequence
12def assure_str(supposed_str) -> str:
13 if not isinstance(supposed_str, str):
14 raise TypeError(f"supposed_str ({supposed_str}) must be a str")
15 return supposed_str
18def assure_str_or_none(supposed_str) -> Optional[str]:
19 if not isinstance(supposed_str, str) and supposed_str is not None:
20 raise TypeError(f"supposed_str ({supposed_str}) must be a str")
21 return supposed_str
24def seq_get(seq: Sequence, defaults: Sequence, index: int):
25 """Get an element from a sequence by index. If the index is out of bounds,
26 get it from the default sequence.
28 Examples:
30 >>> seq_get([1, 2], [5, 6, 7, 8], 2)
31 7
32 >>> seq_get([1, 2], [5, 6, 7, 8], -1)
33 8
34 >>> seq_get([1, 2], [5, 6], -1)
35 2
36 """
37 if index < 0:
38 length = len(defaults)
39 index = length + index
40 if index < 0:
41 raise IndexError(
42 "sequence index out of range in both seq and defaults"
43 )
44 try:
45 return seq[index]
46 except IndexError:
47 try:
48 return defaults[index]
49 except IndexError as e:
50 raise IndexError(
51 "sequence index out of range in both seq and defaults"
52 ) from e
55def rgb888_to_rgb565(rgb_tuple: Collection[int]) -> int:
56 """Return a rgb595 int of an RGB888 color"""
57 red, green, blue = rgb_tuple
58 return (
59 (int(red / 255 * 31) << 11)
60 | (int(green / 255 * 63) << 5)
61 | (int(blue / 255 * 31))
62 )
65def bytes_to_int(input_bytes: Iterable) -> int:
66 """Concatenate a tuple of bytes or ints representing them into a single int.
68 For example (hex for easier understanding):
70 >>> hex(bytes_to_int((0xab, 0xcd, 0xef)))
71 >>> '0xabcdef'
72 """
73 result = 0
74 for byte in input_bytes:
75 result <<= 8
76 result |= byte
78 return result
81def sublists_from_iterable(
82 iterable: Iterable, length: int, yield_last_incomplete: bool = True
83) -> Generator:
84 """Yields lists of a certain length from an iterable.
86 This generator yields lists of length `length` from an interable
87 `iterable`.
89 Args:
90 iterable: from which this generator yields lists of elements
91 length: length of lists yielded
92 yield_last_incomplete: if :pycode`True`, yield the last sublist even if
93 it's shorter than `length`; if :pycode:`False`, raise a ValueError
94 if the last sublist is shorter than `length`
96 Yields:
97 `list`\\ s of elements yielded from `iterable`
99 Examples:
100 >>> from csnake.utils import sublists_from_iterable
101 >>> incomplete_ok = sublists_from_iterable(range(5), 4, True)
102 >>> print(list(incomplete_ok))
103 [[0, 1, 2, 3], [4]]
104 >>> incomplete_notok = sublists_from_iterable(range(5), 4, False)
105 >>> print(list(incomplete_notok))
106 ValueError: Input iterable's length is not divisible by sublist length
107 """
108 currentlist = []
109 index = 0
111 for item in iterable:
112 currentlist.append(item)
113 index += 1
114 if index == length:
115 yield currentlist
116 currentlist = []
117 index = 0
118 if currentlist:
119 if yield_last_incomplete:
120 yield currentlist
121 else:
122 raise ValueError(
123 "Input iterable's length is not divisible by sublist length"
124 )