dublib 0.5.2__tar.gz → 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dublib
3
- Version: 0.5.2
3
+ Version: 0.6.1
4
4
  Summary: Коллекция модулей от DUB1401.
5
5
  Author-email: DUB1401 <vlad.milosta@outlook.com>
6
6
  License: This is free and unencumbered software released into the public domain.
@@ -49,6 +49,8 @@ Requires-Dist: fake_useragent
49
49
  Requires-Dist: httpx
50
50
  Requires-Dist: httpx[http2]
51
51
  Requires-Dist: requests
52
+ Provides-Extra: telebot
53
+ Requires-Dist: pyTelegramBotAPI; extra == "telebot"
52
54
 
53
55
  # dublib
54
56
  **dublib** – это библиотека, поставляющая компоненты, требующиеся в проектах [@DUB1401](https://github.com/DUB1401), написанных на Python.
@@ -58,6 +60,7 @@ Requires-Dist: requests
58
60
  * [Methods](https://github.com/DUB1401/dublib/blob/main/docs/Methods.md)
59
61
  * [Polyglot](https://github.com/DUB1401/dublib/blob/main/docs/Polyglot.md)
60
62
  * [StyledPrinter](https://github.com/DUB1401/dublib/blob/main/docs/StyledPrinter.md)
63
+ * [TelebotUtils](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
61
64
  * [Terminalyzer](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
62
65
  * [WebRequestor](https://github.com/DUB1401/dublib/blob/main/docs/WebRequestor.md)
63
66
 
@@ -6,6 +6,7 @@
6
6
  * [Methods](https://github.com/DUB1401/dublib/blob/main/docs/Methods.md)
7
7
  * [Polyglot](https://github.com/DUB1401/dublib/blob/main/docs/Polyglot.md)
8
8
  * [StyledPrinter](https://github.com/DUB1401/dublib/blob/main/docs/StyledPrinter.md)
9
+ * [TelebotUtils](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
9
10
  * [Terminalyzer](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
10
11
  * [WebRequestor](https://github.com/DUB1401/dublib/blob/main/docs/WebRequestor.md)
11
12
 
@@ -3,7 +3,7 @@ requires = ["setuptools", "cython"]
3
3
 
4
4
  [project]
5
5
  name = "dublib"
6
- version = "0.5.2"
6
+ version = "0.6.1"
7
7
  description = "Коллекция модулей от DUB1401."
8
8
  authors = [
9
9
  {name = "DUB1401", email = "vlad.milosta@outlook.com"}
@@ -30,8 +30,13 @@ classifiers = [
30
30
  "Programming Language :: Python :: 3.13"
31
31
  ]
32
32
 
33
+ [project.optional-dependencies]
34
+ telebot = [
35
+ "pyTelegramBotAPI"
36
+ ]
37
+
33
38
  [project.urls]
34
39
  Documentation = "https://github.com/DUB1401/dublib/tree/main/docs"
35
40
  "Source Code" = "https://github.com/DUB1401/dublib"
36
41
  "Bug Tracker" = "https://github.com/DUB1401/dublib/issues"
37
- Changelog = "https://github.com/DUB1401/dublib/releases"
42
+ Changelog = "https://github.com/DUB1401/dublib/releases"
@@ -0,0 +1,13 @@
1
+ class UpdateByOtherUser(Exception):
2
+ """Исключение: использование данных другого пользователя для обновления."""
3
+
4
+ def __init__(self):
5
+ """Исключение: использование данных другого пользователя для обновления."""
6
+
7
+ # Добавление данных в сообщение об ошибке.
8
+ self.__Message = "Current user ID and ID in updating method differ."
9
+ # Обеспечение доступа к оригиналу наследованного свойства.
10
+ super().__init__(self.__Message)
11
+
12
+ def __str__(self):
13
+ return self.__Message
@@ -96,6 +96,41 @@ def CheckForCyrillicPresence(text: str) -> bool:
96
96
 
97
97
  return IsTextContainsCyrillicCharacters
98
98
 
99
+ def ChunkList(value: list, length: int) -> list[list]:
100
+ """
101
+ Разделяет список на фрагменты фиксированной длинны.
102
+ value – обрабатываемое значение;
103
+ length – длина фрагментов.
104
+ """
105
+
106
+ # Список списков.
107
+ Result = list()
108
+ # Индекс обрезки.
109
+ CutIndex = 1
110
+ # Буфер обрезки.
111
+ Buffer = list()
112
+
113
+ # Для каждого элемента.
114
+ for Index in range(len(value)):
115
+
116
+ # Если индекс обрезки совпадает с длиной.
117
+ if CutIndex == length:
118
+ # Запись и обнуление буфера.
119
+ Result.append(Buffer)
120
+ Buffer = list()
121
+
122
+ else:
123
+ # Запись элемента в буфер.
124
+ Buffer.append(value[Index])
125
+
126
+ # Инкремент индекса обрезки.
127
+ CutIndex += 1
128
+
129
+ # Если в буфере что-то осталось, записать отдельной строкой.
130
+ if len(Buffer) > 0: Result.append(Buffer)
131
+
132
+ return Result
133
+
99
134
  def IsNotAlpha(text: str) -> bool:
100
135
  """
101
136
  Проверяет, состоит ли строка целиком из небуквенных символов.
@@ -0,0 +1,406 @@
1
+ from .Methods import ReadJSON, WriteJSON
2
+ from .Exceptions.TelebotUtils import *
3
+
4
+ from telebot.types import User
5
+
6
+ import os
7
+
8
+ #==========================================================================================#
9
+ # >>>>> УПРАВЛЕНИЕ ПОЛЬЗОВАТЕЛЯМИ <<<<< #
10
+ #==========================================================================================#
11
+
12
+ class UserData:
13
+ """Объектное представление данных пользователя."""
14
+
15
+ #==========================================================================================#
16
+ # >>>>> СВОЙСТВА ТОЛЬКО ДЛЯ ЧТЕНИЯ <<<<< #
17
+ #==========================================================================================#
18
+
19
+ @property
20
+ def id(self) -> int:
21
+ """ID пользователя."""
22
+
23
+ return self.__ID
24
+
25
+ @property
26
+ def is_premium(self) -> bool:
27
+ """Состояние: есть ли Premium-подписка у пользователя."""
28
+
29
+ return self.__Data["premium"]
30
+
31
+ @property
32
+ def language(self) -> str:
33
+ """Код используемого клиентом языка по стандарту ISO 639-1."""
34
+
35
+ return self.__Data["language"]
36
+
37
+ @property
38
+ def permissions(self) -> list:
39
+ """Список прав доступа пользователя."""
40
+
41
+ return self.__Data["permissions"]
42
+
43
+ @property
44
+ def username(self) -> str:
45
+ """Ник пользователя."""
46
+
47
+ return self.__Data["username"]
48
+
49
+ #==========================================================================================#
50
+ # >>>>> ПРИВАТНЫЕ МЕТОДЫ <<<<< #
51
+ #==========================================================================================#
52
+
53
+ def __SaveData(self):
54
+ """Записывает данные в локальный файл."""
55
+
56
+ # Запись локального файла.
57
+ WriteJSON(self.__StorageDirectory + f"/{self.__ID}.json", self.__Data)
58
+
59
+ #==========================================================================================#
60
+ # >>>>> ПУБЛИЧНЫЕ МЕТОДЫ <<<<< #
61
+ #==========================================================================================#
62
+
63
+ def __init__(self, storage_dir: str, user_id: int, data: dict | None = None):
64
+ """
65
+ Объектное представление данных пользователя.
66
+ storage_dir – путь к директории хранения данных;
67
+ user_id – ID пользователя;
68
+ data – словарь с описанием данных пользователя для инициализации (если не передан, данные будут загружены из файла).
69
+ """
70
+
71
+ #---> Генерация динамических свойств.
72
+ #==========================================================================================#
73
+ # ID пользователя.
74
+ self.__ID = user_id
75
+ # Директория хранилища.
76
+ self.__StorageDirectory = storage_dir.replace("\\", "/").rstrip("/")
77
+ # Словарное представление данных пользователя.
78
+ self.__Data = {
79
+ "username": None,
80
+ "language": None,
81
+ "is_premium": None,
82
+ "permissions": [],
83
+ "data": {}
84
+ }
85
+
86
+ # Если переданы данные в виде словаря.
87
+ if type(data) == dict:
88
+ # Копирование данных.
89
+ self.__Data = data
90
+
91
+ # Если переданы данные в виде объекта.
92
+ elif type(data) == User:
93
+ # Обновление данных.
94
+ self.update(data)
95
+
96
+ # Если существует локальный файл.
97
+ elif os.path.exists(self.__StorageDirectory + f"/{user_id}.json"):
98
+ # Чтение файла.
99
+ self.__Data = ReadJSON(self.__StorageDirectory + f"/{user_id}.json")
100
+
101
+ # Создание файла.
102
+ else:
103
+ # Сохранение данных.
104
+ WriteJSON(self.__StorageDirectory + f"/{user_id}.json", self.__Data)
105
+
106
+ def add_permissions(self, permissions: list[str] | str):
107
+ """
108
+ Задаёт разрешения.
109
+ permissions – разрешения.
110
+ """
111
+
112
+ # Если указано одно разрешение, преобразовать в список.
113
+ if type(permissions) == str: permissions = [permissions]
114
+ # Состояние: изменялся ли список разрешений.
115
+ IsChanged = False
116
+
117
+ # Для каждого разрешения.
118
+ for Permission in permissions:
119
+
120
+ # Если разрешение не определено.
121
+ if Permission not in self.__Data["permissions"]:
122
+ # Добавление разрешения.
123
+ self.__Data["permissions"].append(Permission)
124
+ # Переключение состояния.
125
+ IsChanged = True
126
+
127
+ # Если список разрешений изменён, отсортировать его.
128
+ if IsChanged: self.__Data["permissions"] = sorted(self.__Data["permissions"])
129
+ # Сохранение данных.
130
+ self.__SaveData()
131
+
132
+ def create_property(self, key: str, value: any):
133
+ """
134
+ Создаёт свойство пользователя и задаёт ему значение, если такового ещё не существует.
135
+ key – ключ свойства;
136
+ value – значение.
137
+ """
138
+
139
+ # Если свойства не существует.
140
+ if key not in self.__Data["data"].keys():
141
+ # Создание свойства.
142
+ self.__Data["data"][key] = value
143
+ # Сохранение данных.
144
+ self.__SaveData()
145
+
146
+ def get_property(self, key: str) -> any:
147
+ """
148
+ Возвращает значение свойства пользователя.
149
+ key – ключ свойства.
150
+ """
151
+
152
+ return self.__Data["data"][key]
153
+
154
+ def has_permissions(self, permissions: list[str] | str) -> bool:
155
+ """
156
+ Проверяет, имеет ли пользователь все перечисленные разрешения.
157
+ permissions – разрешения.
158
+ """
159
+
160
+ # Если указано одно разрешение, преобразовать в список.
161
+ if type(permissions) == str: permissions = [permissions]
162
+ # Состояние: имеет ли пользователь все указанные разрешения.
163
+ IsOwned = True
164
+
165
+ # Для каждого разрешения.
166
+ for Permission in permissions:
167
+
168
+ # Если разрешение не определено, переключить состояние.
169
+ if Permission not in self.__Data["permissions"]: IsOwned = False
170
+
171
+ return IsOwned
172
+
173
+ def remove(self):
174
+ """Удаляет локальный файл пользователя."""
175
+
176
+ # Удаление локального файла.
177
+ os.remove(self.__StorageDirectory + f"/{self.__ID}.json")
178
+
179
+ def remove_permissions(self, permissions: list[str] | str):
180
+ """
181
+ Удаляет разрешения.
182
+ permissions – разрешения.
183
+ """
184
+
185
+ # Если указано одно разрешение, преобразовать в список.
186
+ if type(permissions) == str: permissions = [permissions]
187
+
188
+ # Для каждого разрешения.
189
+ for Permission in permissions:
190
+
191
+ # Если разрешение определено.
192
+ if Permission in self.__Data["permissions"]:
193
+ # Удаление разрешения.
194
+ self.__Data["permissions"].remove(Permission)
195
+
196
+ # Сохранение данных.
197
+ self.__SaveData()
198
+
199
+ def remove_property(self, key: str):
200
+ """
201
+ Удаляет свойство пользователя.
202
+ key – ключ свойства.
203
+ """
204
+
205
+ # Если свойство существует.
206
+ if key in self.__Data["data"].keys():
207
+ # Удаление свойства.
208
+ del self.__Data["data"][key]
209
+ # Сохранение данных.
210
+ self.__SaveData()
211
+
212
+ def set_property(self, key: str, value: any):
213
+ """
214
+ Обновляет значение существующего свойства пользователя.
215
+ key – ключ свойства;
216
+ value – значение.
217
+ """
218
+
219
+ # Если свойство существует.
220
+ if key in self.__Data["data"].keys():
221
+ # Обновление данных.
222
+ self.__Data["data"][key] = value
223
+ # Сохранение данных.
224
+ self.__SaveData()
225
+
226
+ def update(self, user: User):
227
+ """
228
+ Обновляет данные пользователя из параметров, содержащихся в сообщении.
229
+ user – объект представления пользователя.
230
+ """
231
+
232
+ # Если ID соответствует.
233
+ if user.id == self.__ID:
234
+ # Обновление данных.
235
+ self.__Data["is_premium"] = bool(user.is_premium)
236
+ self.__Data["language"] = user.language_code
237
+ self.__Data["username"] = user.username
238
+ # Сохранение файла.
239
+ self.__SaveData()
240
+
241
+ else: raise UpdateByOtherUser()
242
+
243
+ class UsersManager:
244
+ """Менеджер пользователей."""
245
+
246
+ #==========================================================================================#
247
+ # >>>>> СВОЙСТВА ТОЛЬКО ДЛЯ ЧТЕНИЯ <<<<< #
248
+ #==========================================================================================#
249
+
250
+ @property
251
+ def admins(self) -> list[UserData]:
252
+ """Список пользователей с правами администратора."""
253
+
254
+ # Список администраторов.
255
+ Admins = list()
256
+
257
+ # Для каждого пользователя.
258
+ for UserID in self.__Users.keys():
259
+ # Добавление пользователя в список.
260
+ if self.__Users[UserID].is_admin: Admins.append(self.__Users[UserID])
261
+
262
+ return Admins
263
+
264
+ @property
265
+ def premium_users(self) -> list[UserData]:
266
+ """Список пользователей с Premium подпиской."""
267
+
268
+ # Список подписчиков.
269
+ PremiumUsers = list()
270
+
271
+ # Для каждого пользователя.
272
+ for UserID in self.__Users:
273
+ # Добавление пользователя в список.
274
+ if self.__Users[UserID].is_premium: PremiumUsers.append(self.__Users[UserID])
275
+
276
+ return PremiumUsers
277
+
278
+ @property
279
+ def users(self) -> list[UserData]:
280
+ """Список пользователей."""
281
+
282
+ # Список пользователей.
283
+ Users = list()
284
+ # Для каждого пользователя записать значение в список.
285
+ for UserID in self.__Users.keys(): Users.append(self.__Users[UserID])
286
+
287
+ return Users
288
+
289
+ #==========================================================================================#
290
+ # >>>>> МЕТОДЫ <<<<< #
291
+ #==========================================================================================#
292
+
293
+ def __LoadUsers(self):
294
+ """Загружает данные пользователей."""
295
+
296
+ # Получение списка файлов в директории пользователей.
297
+ Files = os.listdir(self.__StorageDirectory)
298
+ # Фильтрация только файлов формата JSON.
299
+ Files = list(filter(lambda List: List.endswith(".json"), Files))
300
+
301
+ # Для каждого файла.
302
+ for File in Files:
303
+ # Чтение файла.
304
+ Buffer = ReadJSON(self.__StorageDirectory + f"/{File}")
305
+ # ID пользователя.
306
+ UserID = int(File.replace(".json", ""))
307
+ # Запись пользовательских данных.
308
+ self.__Users[UserID] = UserData(self.__StorageDirectory, UserID, Buffer)
309
+
310
+ def __init__(self, dir: str):
311
+ """
312
+ Менеджер пользователей.
313
+ dir – путь к директории хранения данных.
314
+ """
315
+
316
+ #---> Генерация динамических свойств.
317
+ #==========================================================================================#
318
+ # Словарь пользователей.
319
+ self.__Users = dict()
320
+ # Директория хранилища.
321
+ self.__StorageDirectory = dir.replace("\\", "/").rstrip("/")
322
+
323
+ # Если директория пользователей не существует, создать её.
324
+ if not os.path.exists(self.__StorageDirectory): os.makedirs(self.__StorageDirectory)
325
+ # Загрузка данных пользователей.
326
+ self.__LoadUsers()
327
+
328
+ def auth(self, user: User) -> UserData:
329
+ """
330
+ Выполняет идентификацию и обновление данных существующего пользователя или создаёт локальный файл для нового.
331
+ user – структура описания пользователя Telegram.
332
+ """
333
+
334
+ # Текущий пользователь.
335
+ CurrentUser = None
336
+
337
+ # Если пользователь ещё не существует.
338
+ if user.id not in self.__Users.keys():
339
+ # Создание нового пользователя.
340
+ self.__Users[user.id] = UserData(self.__StorageDirectory, user.id, user)
341
+
342
+ # Обновление данных пользователя.
343
+ self.__Users[user.id].update(user)
344
+ # Установка текущего пользователя.
345
+ CurrentUser = self.__Users[user.id]
346
+
347
+ return CurrentUser
348
+
349
+ def get_user(self, user_id: int | str) -> UserData:
350
+ """
351
+ Возвращает объект данных пользователя.
352
+ user_id – ID пользователя.
353
+ """
354
+
355
+ return self.__Users[int(user_id)]
356
+
357
+ def get_users(self, include_permissions: list[str] | str | None = None, exclude_permissions: list[str] | str | None = None) -> list[UserData]:
358
+ """
359
+ Возвращает список пользователей, подходящих под переданные фильтры. По умолчанию возвращает список всех пользователей.
360
+ include_permissions – разрешения, которыми должен обладать пользователь;
361
+ exclude_permissions – разрешения, которых у пользователя быть не должно.
362
+ """
363
+
364
+ # Копирование списка пользователей.
365
+ Users = self.users
366
+
367
+ # Если переданы включения разрешений для фильтрации.
368
+ if include_permissions:
369
+ # Буфер фильтрации.
370
+ Buffer = list()
371
+
372
+ # Для каждого пользователя.
373
+ for User in Users:
374
+ # Если пользователь имеет все указанные разрешения, записать его.
375
+ if User.has_permissions(include_permissions): Buffer.append(User)
376
+
377
+ # Перезапись списка пользователей буфером.
378
+ Users = Buffer
379
+
380
+ # Если переданы исключения разрешений для фильтрации.
381
+ if exclude_permissions:
382
+ # Буфер фильтрации.
383
+ Buffer = list()
384
+
385
+ # Для каждого пользователя.
386
+ for User in Users:
387
+ # Если пользователь не имеет все указанные разрешения, записать его.
388
+ if not User.has_permissions(exclude_permissions): Buffer.append(User)
389
+
390
+ # Перезапись списка пользователей буфером.
391
+ Users = Buffer
392
+
393
+ return Users
394
+
395
+ def remove_user(self, user_id: int | str):
396
+ """
397
+ Удаляет пользователя из системы.
398
+ user_id – ID пользователя.
399
+ """
400
+
401
+ # Приведение ID пользователя к целочисленному.
402
+ user_id = int(user_id)
403
+ # Удаление локального файла.
404
+ self.__Users[user_id].remove()
405
+ # Удаление объекта.
406
+ del self.__Users[user_id]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dublib
3
- Version: 0.5.2
3
+ Version: 0.6.1
4
4
  Summary: Коллекция модулей от DUB1401.
5
5
  Author-email: DUB1401 <vlad.milosta@outlook.com>
6
6
  License: This is free and unencumbered software released into the public domain.
@@ -49,6 +49,8 @@ Requires-Dist: fake_useragent
49
49
  Requires-Dist: httpx
50
50
  Requires-Dist: httpx[http2]
51
51
  Requires-Dist: requests
52
+ Provides-Extra: telebot
53
+ Requires-Dist: pyTelegramBotAPI; extra == "telebot"
52
54
 
53
55
  # dublib
54
56
  **dublib** – это библиотека, поставляющая компоненты, требующиеся в проектах [@DUB1401](https://github.com/DUB1401), написанных на Python.
@@ -58,6 +60,7 @@ Requires-Dist: requests
58
60
  * [Methods](https://github.com/DUB1401/dublib/blob/main/docs/Methods.md)
59
61
  * [Polyglot](https://github.com/DUB1401/dublib/blob/main/docs/Polyglot.md)
60
62
  * [StyledPrinter](https://github.com/DUB1401/dublib/blob/main/docs/StyledPrinter.md)
63
+ * [TelebotUtils](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
61
64
  * [Terminalyzer](https://github.com/DUB1401/dublib/blob/main/docs/Terminalyzer.md)
62
65
  * [WebRequestor](https://github.com/DUB1401/dublib/blob/main/docs/WebRequestor.md)
63
66
 
@@ -4,6 +4,7 @@ pyproject.toml
4
4
  src/dublib/Methods.py
5
5
  src/dublib/Polyglot.py
6
6
  src/dublib/StyledPrinter.py
7
+ src/dublib/TelebotUtils.py
7
8
  src/dublib/Terminalyzer.py
8
9
  src/dublib/WebRequestor.py
9
10
  src/dublib/__init__.py
@@ -13,6 +14,7 @@ src/dublib.egg-info/dependency_links.txt
13
14
  src/dublib.egg-info/requires.txt
14
15
  src/dublib.egg-info/top_level.txt
15
16
  src/dublib/Exceptions/StyledPrinter.py
17
+ src/dublib/Exceptions/TelebotUtils.py
16
18
  src/dublib/Exceptions/Terminalyzer.py
17
19
  src/dublib/Exceptions/WebRequestor.py
18
20
  src/dublib/Exceptions/__init__.py
@@ -3,3 +3,6 @@ fake_useragent
3
3
  httpx
4
4
  httpx[http2]
5
5
  requests
6
+
7
+ [telebot]
8
+ pyTelegramBotAPI
File without changes
File without changes
File without changes
File without changes