Passed
Push — master ( fd05b8...265ada )
by torrua
02:26
created

keyboa.base.Base.items_in_row()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 2
dl 0
loc 3
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
# -*- coding:utf-8 -*-
2 1
"""
3
This module contains basic class with initial Keyboa data.
4
"""
5
# pylint: disable = C0116
6
7 1
from typing import Union, Iterable
8 1
from telebot.types import InlineKeyboardMarkup
9 1
from keyboa.button import Button
10 1
from keyboa.constants import (
11
    BlockItems,
12
    CallbackDataMarker,
13
    MAXIMUM_ITEMS_IN_KEYBOARD,
14
    MINIMUM_ITEMS_IN_LINE,
15
    MAXIMUM_ITEMS_IN_LINE,
16
)
17
18
19 1
class Base:  # pylint: disable = R0902
20
    """
21
    Base initial class for Keyboa
22
    """
23
24 1
    def __init__(  # pylint: disable = R0913
25
        self,
26
        items: BlockItems,
27
        items_in_row: int = None,
28
        front_marker: CallbackDataMarker = str(),
29
        back_marker: CallbackDataMarker = str(),
30
        copy_text_to_callback: bool = False,
31
        alignment: Union[bool, Iterable] = None,
32
        alignment_reverse_range: bool = None,
33
    ):
34 1
        self._items = None
35 1
        self.items = items
36
37 1
        self._items_in_row = None
38 1
        self.items_in_row = items_in_row
39
40 1
        self._front_marker = str()
41 1
        self.front_marker = front_marker
42
43 1
        self._back_marker = str()
44 1
        self.back_marker = back_marker
45
46 1
        self._copy_text_to_callback = False
47 1
        self.copy_text_to_callback = copy_text_to_callback
48
49 1
        self._alignment = None
50 1
        self.alignment = alignment
51
52 1
        self._alignment_reverse_range = None
53 1
        self.alignment_reverse_range = alignment_reverse_range
54
55 1
        self._items_sliced = None
56
57 1
    @property
58 1
    def items(self) -> BlockItems:
59 1
        return self._items
60
61 1
    @items.setter
62 1
    def items(self, items_value) -> None:
63 1
        if items_value is None or not items_value:
64 1
            raise ValueError("Items should not be None")
65 1
        if not isinstance(items_value, list):
66 1
            items_value = [
67
                items_value,
68
            ]
69
70 1
        self.is_all_items_in_limits(items_value)
71 1
        self._items = items_value
72
73 1
    @property
74 1
    def items_in_row(self) -> int:
75 1
        return self._items_in_row
76
77 1
    @items_in_row.setter
78 1
    def items_in_row(self, items_in_row_value) -> None:
79 1
        self.is_items_in_row_limits(items_in_row_value)
80 1
        self._items_in_row = items_in_row_value
81
82 1
    @property
83 1
    def front_marker(self) -> CallbackDataMarker:
84 1
        return self._front_marker
85
86 1
    @front_marker.setter
87 1
    def front_marker(self, front_marker_value) -> None:
88 1
        Button.get_checked_marker(front_marker_value)
89 1
        self._front_marker = front_marker_value
90
91 1
    @property
92 1
    def back_marker(self) -> CallbackDataMarker:
93 1
        return self._back_marker
94
95 1
    @back_marker.setter
96 1
    def back_marker(self, back_marker_value) -> None:
97 1
        Button.get_checked_marker(back_marker_value)
98 1
        self._back_marker = back_marker_value
99
100 1
    @property
101 1
    def copy_text_to_callback(self) -> bool:
102 1
        return self._copy_text_to_callback
103
104 1
    @copy_text_to_callback.setter
105 1
    def copy_text_to_callback(self, copy_text_to_callback_value) -> None:
106 1
        if not isinstance(copy_text_to_callback_value, bool):
107 1
            raise TypeError("'copy_text_to_callback' should have only bool type")
108 1
        self._copy_text_to_callback = copy_text_to_callback_value
109
110 1
    @property
111 1
    def alignment(self) -> Union[bool, Iterable]:
112
113 1
        return self._alignment
114
115 1
    @alignment.setter
116 1
    def alignment(self, alignment_value) -> None:
117 1
        if alignment_value is None or isinstance(alignment_value, bool):
118 1
            self._alignment = alignment_value
119 1
            return
120 1
        self.is_alignment_iterable(alignment_value)
121 1
        self.is_alignment_in_limits(alignment_value)
122 1
        self._alignment = alignment_value
123
124 1
    @property
125 1
    def alignment_reverse_range(self) -> bool:
126 1
        return self._alignment_reverse_range
127
128 1
    @alignment_reverse_range.setter
129 1
    def alignment_reverse_range(self, alignment_reverse_range_value) -> None:
130 1
        self._alignment_reverse_range = alignment_reverse_range_value
131
132 1
    @classmethod
133 1
    def is_all_items_in_limits(cls, items) -> None:
134 1
        items_in_keyboard = sum(
135
            len(row) if isinstance(row, (list, tuple, set)) else 1 for row in items
136
        )
137 1
        if items_in_keyboard > MAXIMUM_ITEMS_IN_KEYBOARD:
138 1
            value_error_message_keyboard = (
139
                "Telegram Bot API limit exceeded: The keyboard should have "
140
                "from 1 to %s buttons at all. Your total amount is %s."
141
            )
142 1
            raise ValueError(
143
                value_error_message_keyboard
144
                % (MAXIMUM_ITEMS_IN_KEYBOARD, items_in_keyboard)
145
            )
146
147 1
        if all(isinstance(line, list) for line in items):
148 1
            for line in items:
149 1
                cls.is_items_in_row_limits(len(line))
150
151 1
    @staticmethod
152 1
    def is_items_in_row_limits(items_in_row) -> None:
153 1
        if items_in_row is not None and (
154
            MINIMUM_ITEMS_IN_LINE > items_in_row or items_in_row > MAXIMUM_ITEMS_IN_LINE
155
        ):
156 1
            value_error_message_line = (
157
                "Telegram Bot API limit exceeded: "
158
                "The keyboard line should have from 1 to %s buttons. You entered %s."
159
            )
160 1
            raise ValueError(
161
                value_error_message_line % (MAXIMUM_ITEMS_IN_LINE, items_in_row)
162
            )
163
164 1
    @staticmethod
165 1
    def is_alignment_in_limits(auto_alignment) -> None:
166
        """
167
        :param auto_alignment:
168
        :return:
169
        """
170 1
        if (
171
            max(auto_alignment) > MAXIMUM_ITEMS_IN_LINE
172
            or min(auto_alignment) < MINIMUM_ITEMS_IN_LINE
173
        ):
174 1
            value_error_message = (
175
                "The auto_alignment's item values should be between "
176
                "%s and %s. You entered: %s\n"
177
                "You may define it as 'True' to use AUTO_ALIGNMENT_RANGE."
178
                % (MINIMUM_ITEMS_IN_LINE, MAXIMUM_ITEMS_IN_LINE, auto_alignment)
179
            )
180 1
            raise ValueError(value_error_message)
181
182 1
    @staticmethod
183 1
    def is_alignment_iterable(auto_alignment) -> None:
184
        """
185
        :param auto_alignment:
186
        :return:
187
        """
188 1
        if not (
189
            isinstance(auto_alignment, Iterable)
190
            and all(map(lambda s: isinstance(s, int), auto_alignment))
191
        ):
192 1
            type_error_message = (
193
                "The auto_alignment variable has not a proper type. "
194
                "Only Iterable of integers or boolean type allowed.\n"
195
                "You may define it as 'True' to use AUTO_ALIGNMENT_RANGE."
196
            )
197 1
            raise TypeError(type_error_message)
198
199 1
    @staticmethod
200 1
    def is_keyboard_proper_type(keyboard) -> None:
201 1
        if keyboard and not isinstance(keyboard, InlineKeyboardMarkup):
202 1
            type_error_message = (
203
                "Keyboard to which the new items will be added "
204
                "should have InlineKeyboardMarkup type. Now it is a %s" % type(keyboard)
205
            )
206
            raise TypeError(type_error_message)
207