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""" 

5 

6from typing import Collection 

7from typing import Generator 

8from typing import Iterable 

9from typing import Optional 

10from typing import Sequence 

11 

12 

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 

17 

18 

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 

23 

24 

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. 

28 

29 Examples: 

30 

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 

54 

55 

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 ) 

64 

65 

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

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

68 

69 For example (hex for easier understanding): 

70 

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 

78 

79 return result 

80 

81 

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. 

86 

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

88 `iterable`. 

89 

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` 

96 

97 Yields: 

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

99 

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 

111 

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 )