Hide keyboard shortcuts

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 

10 

11 

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 

16 

17 

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 

22 

23 

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. 

27 

28 Examples: 

29 

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 

53 

54 

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 ) 

63 

64 

65def bytes_to_int(input_bytes: Iterable) -> int: 

66 """Concatenate a tuple of bytes or ints representing them into a single int. 

67 

68 For example (hex for easier understanding): 

69 

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 

77 

78 return result 

79 

80 

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. 

85 

86 This generator yields lists of length `length` from an interable 

87 `iterable`. 

88 

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` 

95 

96 Yields: 

97 `list`\\ s of elements yielded from `iterable` 

98 

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 

110 

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 )