Passed
Push — master ( c202b7...4e2049 )
by torrua
05:26 queued 11s
created

keyboa.keyboard.Keyboa.slice()   A

Complexity

Conditions 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 16
rs 9.9
c 0
b 0
f 0
cc 2
nop 2
1
# -*- coding:utf-8 -*-
2
"""
3
This module contains all the necessary functions for
4
creating complex and functional inline keyboards.
5
"""
6
7
8
from typing import Union, Optional, Tuple
9
from telebot.types import InlineKeyboardMarkup
10
11
from keyboa.base import Base
12
from keyboa.button import Button
13
from keyboa.constants import (
14
    DEFAULT_ITEMS_IN_LINE,
15
    AUTO_ALIGNMENT_RANGE,
16
)
17
18
19
class Keyboa(Base):
20
    """Default Keyboa class"""
21
22
    def slice(
23
        self,
24
        slice_: slice = slice(None, None, None),
25
    ) -> InlineKeyboardMarkup:
26
        """
27
        :return:
28
        """
29
        self._items_sliced = self.items[slice_]
30
31
        keyboard = (
32
            self._generated_keyboa
33
            if self.items_in_row or self.alignment
34
            else self._preformatted_keyboa
35
        )
36
        self._items_sliced = None
37
        return keyboard
38
39
    @property
40
    def keyboard(self) -> InlineKeyboardMarkup:
41
        """
42
        :return:
43
        """
44
        return self.slice()
45
46
    @property
47
    def _calculated_items_in_row(self) -> Optional[int]:
48
        """
49
        :return:
50
        """
51
52
        items_in_row = None
53
54
        for divider in self.alignment_range:
55
            if not len(self._items_sliced) % divider:
56
                items_in_row = divider
57
                break
58
59
        return items_in_row
60
61
    @property
62
    def _verified_items_in_row(self) -> int:
63
        """
64
        :return:
65
        """
66
        items_in_row = self.items_in_row
67
        if self.alignment:
68
            items_in_row = self._calculated_items_in_row
69
70
        if not items_in_row:
71
            items_in_row = DEFAULT_ITEMS_IN_LINE
72
        return items_in_row
73
74
    @property
75
    def alignment_range(self):
76
        """
77
        :return:
78
        """
79
80
        alignment_range = (
81
            AUTO_ALIGNMENT_RANGE if isinstance(self.alignment, bool) else self.alignment
82
        )
83
        return (
84
            reversed(alignment_range)
85
            if self.alignment_reverse_range
86
            else alignment_range
87
        )
88
89
    @property
90
    def _preformatted_keyboa(self) -> InlineKeyboardMarkup:
91
        """
92
        :return:
93
        """
94
        self.verify_preformatted_items()
95
        keyboard = InlineKeyboardMarkup()
96
        for row in self._items_sliced:
97
            buttons = self.convert_items_to_buttons(row)
98
            keyboard.row(*buttons)
99
        return keyboard
100
101
    def verify_preformatted_items(self) -> None:
102
        """
103
        Check that every row in kb is a list
104
        :return:
105
        """
106
        for index, item in enumerate(self._items_sliced):
107
            if not isinstance(item, list):
108
                self._items_sliced[index] = [
109
                    item,
110
                ]
111
112
    def convert_items_to_buttons(self, items) -> list:
113
        """
114
        :param items:
115
        :return:
116
        """
117
        return [
118
            Button(
119
                button_data=item,
120
                front_marker=self.front_marker,
121
                back_marker=self.back_marker,
122
                copy_text_to_callback=self.copy_text_to_callback,
123
            ).generate()
124
            for item in items
125
        ]
126
127
    @property
128
    def _generated_keyboa(self) -> InlineKeyboardMarkup:
129
        """
130
        :return:
131
        """
132
        keyboard = InlineKeyboardMarkup()
133
        items_in_row = self._verified_items_in_row
134
        rows_in_keyboard = len(self._items_sliced) // items_in_row
135
        buttons = self.convert_items_to_buttons(self._items_sliced)
136
137
        for _row in range(rows_in_keyboard):
138
            keyboard.row(*[buttons.pop(0) for _button in range(items_in_row)])
139
        keyboard.row(*buttons)
140
141
        return keyboard
142
143
    @staticmethod
144
    def merge_keyboards_data(keyboards):
145
        """
146
        :param keyboards:
147
        :return:
148
        """
149
        data = []
150
        for keyboard in keyboards:
151
            if keyboard is None:
152
                continue
153
154
            if not isinstance(keyboard, InlineKeyboardMarkup):
155
                type_error_message = (
156
                    "Keyboard cannot be %s. Only InlineKeyboardMarkup allowed."
157
                    % type(keyboard)
158
                )
159
                raise TypeError(type_error_message)
160
            data.extend(keyboard.keyboard)
161
        return data
162
163
    @classmethod
164
    def combine(
165
        cls,
166
        keyboards: Optional[
167
            Union[Tuple[InlineKeyboardMarkup, ...], InlineKeyboardMarkup]
168
        ] = None,
169
    ) -> InlineKeyboardMarkup:
170
        """
171
        This function combines multiple InlineKeyboardMarkup objects into one.
172
173
        :param keyboards: Sequence of InlineKeyboardMarkup objects.
174
            Also could be presented as a standalone InlineKeyboardMarkup.
175
176
        :return: InlineKeyboardMarkup
177
        """
178
179
        if keyboards is None:
180
            return InlineKeyboardMarkup()
181
182
        if isinstance(keyboards, InlineKeyboardMarkup):
183
            keyboards = (keyboards,)
184
185
        for keyboard in keyboards:
186
            cls.is_keyboard_proper_type(keyboard)
187
188
        data = cls.merge_keyboards_data(keyboards)
189
190
        return cls(items=data).keyboard
191