Rubka 6.4.8__py3-none-any.whl → 6.5.2__py3-none-any.whl

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.
rubka/api.py CHANGED
@@ -3,6 +3,7 @@ from typing import List, Optional, Dict, Any, Literal
3
3
  from .exceptions import APIRequestError
4
4
  from .adaptorrubka import Client as Client_get
5
5
  from .logger import logger
6
+ from . import filters
6
7
  from typing import Callable
7
8
  from .context import Message,InlineMessage
8
9
  from typing import Optional, Union, Literal, Dict, Any
@@ -489,14 +490,28 @@ class Robot:
489
490
 
490
491
  return decorator
491
492
 
492
- def on_message(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
493
+ def on_message(
494
+ self,
495
+ filters: Optional[Callable[[Message], bool]] = None,
496
+ commands: Optional[List[str]] = None
497
+ ):
493
498
  def decorator(func: Callable[[Any, Message], None]):
499
+ def wrapper(bot, message: Message):
500
+ if filters and not filters(message):
501
+ return
502
+ if commands:
503
+ if not getattr(message, "is_command", False):
504
+ return
505
+ cmd = message.text.split()[0].lstrip("/") if message.text else ""
506
+ if cmd not in commands:
507
+ return
508
+ return func(bot, message)
494
509
  self._message_handlers.append({
495
- "func": func,
510
+ "func": wrapper,
496
511
  "filters": filters,
497
512
  "commands": commands
498
513
  })
499
- return func
514
+ return wrapper
500
515
  return decorator
501
516
  def on_message_file(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
502
517
  def decorator(func: Callable[[Any, Message], None]):
rubka/asynco.py CHANGED
@@ -5,6 +5,7 @@ from typing import List, Optional, Dict, Any, Literal, Callable, Union
5
5
  from .exceptions import APIRequestError
6
6
  from .adaptorrubka import Client as Client_get
7
7
  from .logger import logger
8
+ from . import filters
8
9
  try:
9
10
  from .context import Message, InlineMessage
10
11
  except (ImportError, ModuleNotFoundError):
@@ -527,15 +528,27 @@ class Robot:
527
528
  return wrapper
528
529
  return decorator
529
530
 
530
- def on_message(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
531
+ def on_message(
532
+ self,
533
+ filters: Optional[Callable[[Message], bool]] = None,
534
+ commands: Optional[List[str]] = None
535
+ ):
531
536
  def decorator(func: Callable[[Any, Message], None]):
537
+ async def wrapper(bot, message: Message):
538
+ if filters and not filters(message):return
539
+ if commands:
540
+ if not message.is_command:return
541
+ cmd = message.text.split()[0].lstrip("/")
542
+ if cmd not in commands:return
543
+ return await func(bot, message)
532
544
  self._message_handlers.append({
533
- "func": func,
545
+ "func": wrapper,
534
546
  "filters": filters,
535
547
  "commands": commands
536
548
  })
537
- return func
549
+ return wrapper
538
550
  return decorator
551
+
539
552
 
540
553
  def on_message_file(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
541
554
  def decorator(func: Callable[[Any, Message], None]):
rubka/filters.py ADDED
@@ -0,0 +1,317 @@
1
+ from typing import Callable
2
+ import re
3
+
4
+ class Filter:
5
+ def __init__(self, func: Callable):
6
+ self.func = func
7
+
8
+ def __call__(self, message):
9
+ return self.func(message)
10
+
11
+ def __and__(self, other):
12
+ return Filter(lambda m: self(m) and other(m))
13
+
14
+ def __or__(self, other):
15
+ return Filter(lambda m: self(m) or other(m))
16
+
17
+ def __invert__(self):
18
+ return Filter(lambda m: not self(m))
19
+
20
+ def __xor__(self, other):
21
+ return Filter(lambda m: self(m) != other(m))
22
+
23
+ def __eq__(self, other):
24
+ return Filter(lambda m: self(m) == other)
25
+
26
+ def __ne__(self, other):
27
+ return Filter(lambda m: self(m) != other)
28
+
29
+ def __lt__(self, other):
30
+ return Filter(lambda m: self(m) < other)
31
+
32
+ def __le__(self, other):
33
+ return Filter(lambda m: self(m) <= other)
34
+
35
+ def __gt__(self, other):
36
+ return Filter(lambda m: self(m) > other)
37
+
38
+ def __ge__(self, other):
39
+ return Filter(lambda m: self(m) >= other)
40
+
41
+ def __add__(self, other):
42
+ return Filter(lambda m: self(m) + (other(m) if callable(other) else other))
43
+
44
+ def __sub__(self, other):
45
+ return Filter(lambda m: self(m) - (other(m) if callable(other) else other))
46
+
47
+ def __mul__(self, other):
48
+ return Filter(lambda m: self(m) * (other(m) if callable(other) else other))
49
+
50
+ def __truediv__(self, other):
51
+ return Filter(lambda m: self(m) / (other(m) if callable(other) else other))
52
+
53
+ is_text = Filter(lambda m: getattr(m, "is_text", False))
54
+ is_file = Filter(lambda m: getattr(m, "file", None) is not None)
55
+ is_sticker = Filter(lambda m: getattr(m, "sticker", None) is not None)
56
+ is_contact = Filter(lambda m: getattr(m, "contact_message", None) is not None)
57
+ is_poll = Filter(lambda m: getattr(m, "poll", None) is not None)
58
+ is_location = Filter(lambda m: getattr(m, "location", None) is not None)
59
+ is_live_location = Filter(lambda m: getattr(m, "live_location", None) is not None)
60
+ has_any_media = Filter(lambda m: getattr(m, "has_any_media", False))
61
+ has_media = Filter(lambda m: getattr(m, "has_media", False))
62
+ is_command = Filter(lambda m: getattr(m, "is_command", False))
63
+ is_user = Filter(lambda m: getattr(m, "is_user", False))
64
+ is_private = Filter(lambda m: getattr(m, "is_private", False))
65
+ is_group = Filter(lambda m: getattr(m, "is_group", False))
66
+ is_channel = Filter(lambda m: getattr(m, "is_channel", False))
67
+ is_reply = Filter(lambda m: getattr(m, "is_reply", False))
68
+ is_forwarded = Filter(lambda m: getattr(m, "is_forwarded", False))
69
+ is_edited = Filter(lambda m: getattr(m, "is_edited", False))
70
+
71
+
72
+
73
+
74
+ def text(keyword: str):
75
+ return Filter(lambda m: getattr(m, "text", "") and keyword in m.text)
76
+
77
+ def text_length(min_len: int = 0, max_len: int = None):
78
+ def _filter(m):
79
+ t = getattr(m, "text", "")
80
+ if not t: return False
81
+ if len(t) < min_len: return False
82
+ if max_len is not None and len(t) > max_len: return False
83
+ return True
84
+ return Filter(_filter)
85
+
86
+ def text_regex(pattern: str):
87
+ regex = re.compile(pattern)
88
+ return Filter(lambda m: getattr(m, "text", "") and regex.search(m.text))
89
+
90
+ def text_startswith(prefix: str):
91
+ return Filter(lambda m: getattr(m, "text", "").startswith(prefix) if getattr(m, "text", None) else False)
92
+
93
+ def text_endswith(suffix: str):
94
+ return Filter(lambda m: getattr(m, "text", "").endswith(suffix) if getattr(m, "text", None) else False)
95
+
96
+ def text_upper():
97
+ return Filter(lambda m: getattr(m, "text", "").isupper() if getattr(m, "text", None) else False)
98
+
99
+ def text_lower():
100
+ return Filter(lambda m: getattr(m, "text", "").islower() if getattr(m, "text", None) else False)
101
+
102
+ def text_digit():
103
+ return Filter(lambda m: getattr(m, "text", "").isdigit() if getattr(m, "text", None) else False)
104
+
105
+ def text_word_count(min_words: int = 1, max_words: int = None):
106
+ def _filter(m):
107
+ t = getattr(m, "text", "")
108
+ if not t: return False
109
+ wc = len(t.split())
110
+ if wc < min_words: return False
111
+ if max_words is not None and wc > max_words: return False
112
+ return True
113
+ return Filter(_filter)
114
+
115
+ def text_contains_any(keywords: list):
116
+ return Filter(lambda m: getattr(m, "text", "") and any(k in m.text for k in keywords))
117
+
118
+ def text_equals(value: str):
119
+ return Filter(lambda m: getattr(m, "text", None) == value)
120
+
121
+ def text_not_equals(value: str):
122
+ return Filter(lambda m: getattr(m, "text", None) != value)
123
+
124
+
125
+
126
+
127
+ def file_size_gt(size: int):
128
+ return Filter(lambda m: m.file and getattr(m.file, "size", 0) > size)
129
+
130
+ def file_size_lt(size: int):
131
+ return Filter(lambda m: m.file and getattr(m.file, "size", 0) < size)
132
+
133
+ def file_name_contains(substring: str):
134
+ return Filter(lambda m: m.file and substring in getattr(m.file, "file_name", ""))
135
+
136
+ def file_extension(ext: str):
137
+ return Filter(lambda m: m.file and getattr(m.file, "file_name", "").endswith(ext))
138
+
139
+ def file_id_is(file_id: str):
140
+ return Filter(lambda m: m.file and getattr(m.file, "file_id", None) == file_id)
141
+
142
+
143
+
144
+
145
+ def sticker_id_is(sid: str):
146
+ return Filter(lambda m: m.sticker and getattr(m.sticker, "sticker_id", None) == sid)
147
+
148
+ def sticker_emoji_is(emoji: str):
149
+ return Filter(lambda m: m.sticker and getattr(m.sticker, "emoji", None) == emoji)
150
+
151
+
152
+
153
+
154
+ def poll_question_contains(keyword: str):
155
+ return Filter(lambda m: m.poll and keyword in getattr(m.poll, "question", ""))
156
+
157
+ def poll_option_count(min_options: int = 1, max_options: int = None):
158
+ def _filter(m):
159
+ if not getattr(m, "poll", None): return False
160
+ options = getattr(m.poll, "options", [])
161
+ if len(options) < min_options: return False
162
+ if max_options is not None and len(options) > max_options: return False
163
+ return True
164
+ return Filter(_filter)
165
+
166
+
167
+
168
+
169
+ def location_within(lat_min, lat_max, long_min, long_max):
170
+ def _filter(m):
171
+ loc = getattr(m, "location", None)
172
+ if not loc: return False
173
+ return lat_min <= getattr(loc, "lat", 0) <= lat_max and long_min <= getattr(loc, "long", 0) <= long_max
174
+ return Filter(_filter)
175
+
176
+ def live_location_within(lat_min, lat_max, long_min, long_max):
177
+ def _filter(m):
178
+ loc = getattr(m, "live_location", None)
179
+ if not loc: return False
180
+ return lat_min <= getattr(loc, "lat", 0) <= lat_max and long_min <= getattr(loc, "long", 0) <= long_max
181
+ return Filter(_filter)
182
+
183
+
184
+
185
+
186
+ def has_media_types(types: list):
187
+ return Filter(lambda m: any(getattr(m, t, None) for t in types))
188
+
189
+ def message_id_is(mid: str):
190
+ return Filter(lambda m: getattr(m, "message_id", None) == mid)
191
+
192
+ def is_reply_to_user(user_id: str):
193
+ return Filter(lambda m: getattr(m, "reply_to_message_id", None) == user_id)
194
+
195
+ def is_forwarded_from(user_id: str):
196
+ return Filter(lambda m: getattr(m.forwarded_from, "sender_id", None) == user_id if getattr(m, "forwarded_from", None) else False)
197
+
198
+ def edited_text_contains(keyword: str):
199
+ return Filter(lambda m: getattr(m, "edited_text", "") and keyword in m.edited_text)
200
+
201
+ def aux_data_contains(key: str, value):
202
+ return Filter(lambda m: getattr(m.aux_data, key, None) == value if getattr(m, "aux_data", None) else False)
203
+
204
+
205
+
206
+
207
+ def file_attr(attr_name):
208
+ return Filter(lambda m: m.file and getattr(m.file, attr_name, None))
209
+
210
+ def sticker_attr(attr_name):
211
+ return Filter(lambda m: m.sticker and getattr(m.sticker, attr_name, None))
212
+
213
+ def poll_attr(attr_name):
214
+ return Filter(lambda m: m.poll and getattr(m.poll, attr_name, None))
215
+
216
+ def location_attr(attr_name):
217
+ return Filter(lambda m: m.location and getattr(m.location, attr_name, None))
218
+
219
+ def live_location_attr(attr_name):
220
+ return Filter(lambda m: m.live_location and getattr(m.live_location, attr_name, None))
221
+
222
+
223
+
224
+
225
+ file_size = file_attr("size")
226
+ file_name = file_attr("file_name")
227
+ sticker_id = sticker_attr("sticker_id")
228
+ poll_question = poll_attr("question")
229
+ location_lat = location_attr("lat")
230
+ location_long = location_attr("long")
231
+ live_location_lat = live_location_attr("lat")
232
+ live_location_long = live_location_attr("long")
233
+
234
+ _custom_filters = {}
235
+ def chat_title_contains(keyword: str):
236
+
237
+ return Filter(lambda m: getattr(m, "chat", None) and keyword in getattr(m.chat, "title", ""))
238
+
239
+ def chat_title_equals(value: str):
240
+
241
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "title", "") == value)
242
+
243
+ def chat_id_is(cid: str):
244
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "id", None) == cid)
245
+
246
+ def chat_member_count(min_count: int = 0, max_count: int = None):
247
+
248
+ def _filter(m):
249
+ c = getattr(m, "chat", None)
250
+ if not c: return False
251
+ count = getattr(c, "member_count", 0)
252
+ if count < min_count: return False
253
+ if max_count is not None and count > max_count: return False
254
+ return True
255
+ return Filter(_filter)
256
+
257
+ def chat_type_is(chat_type: str):
258
+
259
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "type", None) == chat_type)
260
+
261
+ def chat_username_contains(keyword: str):
262
+
263
+ return Filter(lambda m: getattr(m, "chat", None) and keyword in getattr(m.chat, "username", ""))
264
+
265
+ def chat_username_equals(value: str):
266
+
267
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "username", "") == value)
268
+
269
+ def chat_has_link():
270
+
271
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "invite_link", None) is not None)
272
+
273
+ def chat_is_private():
274
+
275
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "type", None) in ["group", "channel"])
276
+
277
+ def chat_member_count_gt(count: int):
278
+
279
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "member_count", 0) > count)
280
+
281
+ def chat_member_count_lt(count: int):
282
+
283
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "member_count", 0) < count)
284
+
285
+ def chat_has_username():
286
+
287
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "username", None) is not None)
288
+
289
+ def chat_type_in(types: list):
290
+
291
+ return Filter(lambda m: getattr(m, "chat", None) and getattr(m.chat, "type", None) in types)
292
+
293
+
294
+ def chat_title_regex(pattern: str):
295
+ regex = re.compile(pattern)
296
+ return Filter(lambda m: getattr(m, "chat", None) and regex.search(getattr(m.chat, "title", "")))
297
+
298
+ def chat_username_regex(pattern: str):
299
+ regex = re.compile(pattern)
300
+ return Filter(lambda m: getattr(m, "chat", None) and regex.search(getattr(m.chat, "username", "")))
301
+ def custom(name):
302
+ def wrapper(func):
303
+ _custom_filters[name] = Filter(func)
304
+ return _custom_filters[name]
305
+ return wrapper
306
+
307
+ def get_custom(name):
308
+ return _custom_filters.get(name)
309
+
310
+ def and_(*filters):
311
+ return Filter(lambda m: all(f(m) for f in filters))
312
+
313
+ def or_(*filters):
314
+ return Filter(lambda m: any(f(m) for f in filters))
315
+
316
+ def not_(filter_):
317
+ return Filter(lambda m: not filter_(m))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 6.4.8
3
+ Version: 6.5.2
4
4
  Summary: A Python library for interacting with Rubika Bot API.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/rubka/blob/main/project_library.zip
@@ -1,11 +1,12 @@
1
1
  rubka/__init__.py,sha256=TR1DABU5Maz2eO62ZEFiwOqNU0dH6l6HZfqRUxeo4eY,194
2
- rubka/api.py,sha256=J0fa4XXjImFulLXAaJY2pbE46e03i-Y5QggxaAZq6xw,68159
3
- rubka/asynco.py,sha256=wiuw2oLaYH5a99W7_37sjP29hXabAbThnkLk1sPIzUk,83919
2
+ rubka/api.py,sha256=Nu9bX0Vv0AGLEHfUDtS7_SQDbaavk8bZghc-pRH5zRk,68691
3
+ rubka/asynco.py,sha256=8zpKldan71TQLcZk7W8h3G2Aya1OSGZs5oqhn9jNlrM,84336
4
4
  rubka/button.py,sha256=vU9OvWXCD4MRrTJ8Xmivd4L471-06zrD2qpZBTw5vjY,13305
5
5
  rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
6
6
  rubka/context.py,sha256=4YZs7DiZD_HWOqY76hwwajG0J-bLy6wjeKtQT3EatZU,19341
7
7
  rubka/decorators.py,sha256=hGwUoE4q2ImrunJIGJ_kzGYYxQf1ueE0isadqraKEts,1157
8
8
  rubka/exceptions.py,sha256=tujZt1XrhWaw-lmdeVadVceUptpw4XzNgE44sAAY0gs,90
9
+ rubka/filters.py,sha256=hvH48ejEEXX5KEt9KlzZWBep6O8F9c2o1agwg-y7mMc,11101
9
10
  rubka/jobs.py,sha256=GvLMLsVhcSEzRTgkvnPISPEBN71suW2xXI0hUaUZPTo,378
10
11
  rubka/keyboards.py,sha256=7nr-dT2bQJVQnQ6RMWPTSjML6EEk6dsBx-4d8pab8xk,488
11
12
  rubka/keypad.py,sha256=yGsNt8W5HtUFBzVF1m_p7GySlu1hwIcSvXZ4BTdrlvg,9558
@@ -34,7 +35,7 @@ rubka/adaptorrubka/types/socket/message.py,sha256=0WgLMZh4eow8Zn7AiSX4C3GZjQTkIg
34
35
  rubka/adaptorrubka/utils/__init__.py,sha256=OgCFkXdNFh379quNwIVOAWY2NP5cIOxU5gDRRALTk4o,54
35
36
  rubka/adaptorrubka/utils/configs.py,sha256=nMUEOJh1NqDJsf9W9PurkN_DLYjO6kKPMm923i4Jj_A,492
36
37
  rubka/adaptorrubka/utils/utils.py,sha256=5-LioLNYX_TIbQGDeT50j7Sg9nAWH2LJUUs-iEXpsUY,8816
37
- rubka-6.4.8.dist-info/METADATA,sha256=2FefyxguhKHS07vKRgGlhhzHBi9ojoGe0U9ymQvDNTg,33335
38
- rubka-6.4.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
- rubka-6.4.8.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
40
- rubka-6.4.8.dist-info/RECORD,,
38
+ rubka-6.5.2.dist-info/METADATA,sha256=ijWtJKisum3EsKK72ILJ9e8B2LL4Z_kqbgqaPO82PFg,33335
39
+ rubka-6.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
+ rubka-6.5.2.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
41
+ rubka-6.5.2.dist-info/RECORD,,
File without changes