keyboa.keyboard.Keyboa._generated_keyboa()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

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