Rubka 7.1.4__py3-none-any.whl → 7.1.5__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.

Potentially problematic release.


This version of Rubka might be problematic. Click here for more details.

rubka/api.py CHANGED
@@ -61,13 +61,7 @@ def check_rubka_version():
61
61
  latest_version = get_latest_version(package_name)
62
62
  if latest_version is None:return
63
63
  if installed_version != latest_version:
64
- print(f"\n\nWARNING: Your installed version of '{package_name}' is OUTDATED and may cause errors or security risks!")
65
- print(f"Installed version : {installed_version}")
66
- print(f"Latest available version : {latest_version}")
67
- print(f"Please update IMMEDIATELY by running:")
68
64
  print(f"\npip install {package_name}=={latest_version}\n")
69
- print(f"Not updating may lead to malfunctions or incompatibility.")
70
- print(f"To see new methods : @rubka_library\n\n")
71
65
 
72
66
  check_rubka_version()
73
67
  def show_last_six_words(text):
rubka/asynco.py CHANGED
@@ -72,14 +72,16 @@ async def check_rubka_version():
72
72
  return
73
73
 
74
74
  if installed_version != latest_version:
75
- print(f"\n\nWARNING: Your installed version of '{package_name}' is OUTDATED and may cause errors or security risks!")
76
- print(f"Installed version : {installed_version}")
77
- print(f"Latest available version : {latest_version}")
78
- print(f"Please update IMMEDIATELY by running:")
79
- print(f"\npip install {package_name}=={latest_version}\n")
80
- print("Not updating may lead to malfunctions or incompatibility.")
81
- print("To see new methods : @rubka_library\n\n")
82
-
75
+ print(f"CRITICAL WARNING: Your installed version of '{package_name}' is outdated.")
76
+ print("This poses a serious risk to stability, security, and compatibility with current features.")
77
+ print(f"- Installed version : {installed_version}")
78
+ print(f"- Latest version : {latest_version}")
79
+ print("\nImmediate action is required.")
80
+ print(f"Run the following command to update safely:")
81
+ print(f"\n pip install {package_name}=={latest_version}\n")
82
+ print("Delaying this update may result in unexpected crashes, data loss, or broken functionality.")
83
+ print("Stay up-to-date to ensure full support and access to the latest improvements.")
84
+ print("For new methods and updates, visit: @rubka_library\n")
83
85
 
84
86
 
85
87
 
@@ -141,11 +143,12 @@ safeSendMode ensures reliable message sending even if replying by message_id fai
141
143
  max_cache_size and max_msg_age help manage duplicate message processing efficiently.
142
144
  """
143
145
 
144
- def __init__(self, token: str, session_name: str = None, auth: str = None, Key: str = None, platform: str = "web", web_hook: str = None, timeout: int = 10, show_progress: bool = False, raise_errors: bool = True,proxy: str = None,retries: int = 2,retry_delay: float = 0.5,user_agent: str = None,safeSendMode = False,max_cache_size: int = 2000,max_msg_age : int = 60):
146
+ def __init__(self, token: str, session_name: str = None, auth: str = None, Key: str = None, platform: str = "web", web_hook: str = None, timeout: int = 10, show_progress: bool = False, raise_errors: bool = True,proxy: str = None,retries: int = 2,retry_delay: float = 0.5,user_agent: str = None,safeSendMode = False,max_cache_size: int = 2000,max_msg_age : int = 60,chunk_size : int = 64 * 1024):
145
147
  self.token = token
146
148
  self._inline_query_handlers: List[dict] = []
147
149
  self.timeout = timeout
148
150
  self.auth = auth
151
+ self.chunk_size = chunk_size
149
152
  self.safeSendMode = safeSendMode
150
153
  self.user_agent = user_agent
151
154
  self.proxy = proxy
@@ -1864,41 +1867,45 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
1864
1867
  if chat_keypad_type: payload["chat_keypad_type"] = chat_keypad_type
1865
1868
  return await self._post("sendLocation", {k: v for k, v in payload.items() if v is not None})
1866
1869
  async def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path]) -> str:
1867
- is_temp_file = False
1868
1870
  session = await self._get_session()
1871
+ is_temp_file = False
1869
1872
  if isinstance(path, str) and path.startswith("http"):
1870
1873
  async with session.get(path) as response:
1871
1874
  if response.status != 200:
1872
1875
  raise Exception(f"Failed to download file from URL ({response.status})")
1873
1876
  content = await response.read()
1874
- with tempfile.NamedTemporaryFile(delete=False) as temp_file:
1875
- temp_file.write(content)
1876
- path = temp_file.name
1877
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
1878
+ tmp.write(content)
1879
+ path = tmp.name
1877
1880
  is_temp_file = True
1881
+
1878
1882
  file_size = os.path.getsize(path)
1879
- progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, unit_divisor=1024, desc=f'Uploading : {name}', bar_format='{l_bar}{bar:100}{r_bar}', colour='cyan', disable=not self.show_progress)
1880
- async def file_progress_generator(file_path, chunk_size=8192):
1883
+ chunk_size = self.chunk_size
1884
+
1885
+ progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, unit_divisor=1024,
1886
+ desc=f'Uploading: {name}', colour='cyan', disable=not getattr(self, 'show_progress', True))
1887
+
1888
+ async def file_generator(file_path):
1881
1889
  async with aiofiles.open(file_path, 'rb') as f:
1882
- while True:
1883
- chunk = await f.read(chunk_size)
1884
- if not chunk:
1885
- break
1890
+ while chunk := await f.read(chunk_size):
1886
1891
  progress_bar.update(len(chunk))
1887
1892
  yield chunk
1888
- data = aiohttp.FormData()
1889
- data.add_field('file', file_progress_generator(path), filename=name, content_type='application/octet-stream')
1893
+
1894
+ form = aiohttp.FormData()
1895
+ form.add_field('file', file_generator(path), filename=name, content_type='application/octet-stream')
1896
+
1890
1897
  try:
1891
- async with session.post(upload_url, data=data) as response:
1898
+ async with session.post(upload_url, data=form, timeout=aiohttp.ClientTimeout(total=None)) as response:
1892
1899
  progress_bar.close()
1893
1900
  if response.status != 200:
1894
- raise Exception(f"Upload failed ({response.status}): {await response.text()}")
1895
-
1896
- json_data = await response.json()
1897
- if is_temp_file:
1898
- os.remove(path)
1899
- return json_data.get('data', {}).get('file_id')
1900
- except :
1901
- raise FeatureNotAvailableError(f"files is not currently supported by the server.")
1901
+ text = await response.text()
1902
+ raise Exception(f"Upload failed ({response.status}): {text}")
1903
+ return (await response.json()).get('data', {}).get('file_id')
1904
+ except Exception as e:
1905
+ raise FeatureNotAvailableError(f"File upload not supported: {e}")
1906
+ finally:
1907
+ if is_temp_file:
1908
+ os.remove(path)
1902
1909
  def get_extension(content_type: str) -> str:
1903
1910
  ext = mimetypes.guess_extension(content_type)
1904
1911
  return ext if ext else ''
@@ -2237,8 +2244,42 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
2237
2244
  def get_all_member(self, channel_guid: str, search_text: str = None, start_id: str = None, just_get_guids: bool = False):
2238
2245
  client = self._get_client()
2239
2246
  return client.get_all_members(channel_guid, search_text, start_id, just_get_guids)
2240
- async def send_poll(self, chat_id: str, question: str, options: List[str]) -> Dict[str, Any]:
2241
- return await self._post("sendPoll", {"chat_id": chat_id, "question": question, "options": options})
2247
+ async def send_poll(
2248
+ self,
2249
+ chat_id: str,
2250
+ question: str,
2251
+ options: List[str],
2252
+ type: Literal["Regular", "Quiz"] = "Regular",
2253
+ allows_multiple_answers: bool = False,
2254
+ is_anonymous: bool = True,
2255
+ correct_option_index: Optional[int] = None,
2256
+ hint: Optional[str] = None,
2257
+ reply_to_message_id: Optional[str] = None,
2258
+ disable_notification: bool = False,
2259
+ show_results : bool = False,
2260
+ inline_keypad : Optional[Dict[str, Any]] = None,
2261
+ chat_keypad: Optional[Dict[str, Any]] = None,
2262
+ chat_keypad_type: Optional[Literal["New", "Remove", "None"]] = None,
2263
+
2264
+ ) -> AttrDict:
2265
+ return await self._post(
2266
+ "sendPoll", {
2267
+ "chat_id": chat_id,
2268
+ "question": question,
2269
+ "options": options,
2270
+ "type": type,
2271
+ "allows_multiple_answers": allows_multiple_answers,
2272
+ "is_anonymous": is_anonymous,
2273
+ "correct_option_index": correct_option_index,
2274
+ "explanation": hint,
2275
+ "show_results":show_results,
2276
+ "reply_to_message_id": reply_to_message_id,
2277
+ "disable_notification": disable_notification,
2278
+ "chat_keypad": chat_keypad,
2279
+ "inline_keypad":inline_keypad,
2280
+ "chat_keypad_type": chat_keypad_type,
2281
+ }
2282
+ )
2242
2283
  async def check_join(self, channel_guid: str, chat_id: str = None) -> Union[bool, list[str]]:
2243
2284
  client = self._get_client()
2244
2285
  if chat_id:
rubka/context.py CHANGED
@@ -1,6 +1,6 @@
1
- from typing import Any, Dict, List,Optional
2
1
  from typing import Union
3
2
  from pathlib import Path
3
+ from typing import List, Optional, Dict, Any, Literal, Callable, Union,Set
4
4
  import re,inspect
5
5
  import asyncio
6
6
  class File:
@@ -336,14 +336,40 @@ class Message:
336
336
  )
337
337
 
338
338
 
339
- def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
340
- return self.bot._post("sendPoll", {
339
+ def reply_poll(
340
+ self,
341
+ question: str,
342
+ options: List[str],
343
+ type: Literal['Regular', 'Quiz'] = "Regular",
344
+ allows_multiple_answers: bool = False,
345
+ is_anonymous: bool = True,
346
+ correct_option_index: Optional[int] = None,
347
+ hint: Optional[str] = None,
348
+ reply_to_message_id: Optional[str] = None,
349
+ disable_notification: bool = False,
350
+ show_results: bool = False,
351
+ inline_keypad: Optional[Dict[str, Any]] = None,
352
+ chat_keypad: Optional[Dict[str, Any]] = None,
353
+ chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
354
+ **kwargs
355
+ ) -> dict:
356
+ payload = {
341
357
  "chat_id": self.chat_id,
342
358
  "question": question,
343
359
  "options": options,
344
- "reply_to_message_id": self.message_id,
345
- **kwargs
346
- })
360
+ "type": type,
361
+ "allows_multiple_answers": allows_multiple_answers,
362
+ "is_anonymous": is_anonymous,
363
+ "correct_option_index": correct_option_index,
364
+ "hint": hint,
365
+ "reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
366
+ "disable_notification": disable_notification,
367
+ "show_results": show_results,
368
+ "inline_keypad": inline_keypad,
369
+ "chat_keypad": chat_keypad,
370
+ "chat_keypad_type": chat_keypad_type,
371
+ }
372
+ return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
347
373
 
348
374
 
349
375
  def reply_document(
@@ -617,13 +643,69 @@ class InlineMessage:
617
643
  if self.chat_id not in self.bot.sessions:
618
644
  self.bot.sessions[self.chat_id] = {}
619
645
  return self.bot.sessions[self.chat_id]
620
- def reply(self, text: str, **kwargs):
621
- return self.bot.send_message(
622
- self.chat_id,
623
- text,
624
- reply_to_message_id=self.message_id,
625
- **kwargs
626
- )
646
+
647
+ def reply(self, text: str, delete_after: int = None, **kwargs):
648
+ async def _reply_async():
649
+ send_func = self.bot.send_message
650
+ if inspect.iscoroutinefunction(send_func):
651
+ msg = await send_func(
652
+ self.chat_id,
653
+ text,
654
+ reply_to_message_id=self.message_id,
655
+ delete_after=delete_after,
656
+ **kwargs
657
+ )
658
+ else:
659
+ msg = send_func(
660
+ self.chat_id,
661
+ text,
662
+ reply_to_message_id=self.message_id,
663
+ delete_after=delete_after,
664
+ **kwargs
665
+ )
666
+ class Pick:
667
+ def __init__(self, bot, chat_id, message_id):
668
+ self.bot = bot
669
+ self.chat_id = chat_id
670
+ self.message_id = message_id
671
+
672
+ def edit(self, new_text):
673
+ async def _edit():
674
+ func = self.bot.edit_message_text
675
+ if inspect.iscoroutinefunction(func):
676
+ await func(self.chat_id, self.message_id, new_text)
677
+ else:
678
+ func(self.chat_id, self.message_id, new_text)
679
+
680
+ try:
681
+ loop = asyncio.get_running_loop()
682
+ if loop.is_running():
683
+ return asyncio.create_task(_edit())
684
+ except RuntimeError:
685
+ return asyncio.run(_edit())
686
+
687
+ def delete(self):
688
+ async def _delete():
689
+ func = self.bot.delete_message
690
+ if inspect.iscoroutinefunction(func):
691
+ await func(self.chat_id, self.message_id)
692
+ else:
693
+ func(self.chat_id, self.message_id)
694
+ try:
695
+ loop = asyncio.get_running_loop()
696
+ if loop.is_running():
697
+ return asyncio.create_task(_delete())
698
+ except RuntimeError:
699
+ return asyncio.run(_delete())
700
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
701
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
702
+ return Pick(self.bot, chat_id, message_id)
703
+ try:
704
+ loop = asyncio.get_running_loop()
705
+ if loop.is_running():
706
+ return asyncio.create_task(_reply_async())
707
+ except RuntimeError:
708
+ return asyncio.run(_reply_async())
627
709
  def answer(self, text: str, **kwargs):
628
710
  return self.bot.send_message(
629
711
  self.chat_id,
@@ -631,6 +713,7 @@ class InlineMessage:
631
713
  reply_to_message_id=self.message_id,
632
714
  **kwargs
633
715
  )
716
+
634
717
 
635
718
  def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
636
719
  return self.bot._post("sendPoll", {
@@ -841,4 +924,12 @@ class InlineMessage:
841
924
  return self.bot.delete_message(
842
925
  chat_id=self.chat_id,
843
926
  message_id=self.message_id
844
- )
927
+ )
928
+ @hybrid_property
929
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
930
+ @hybrid_property
931
+ async def name(self):return await self.bot.get_name(self.chat_id)
932
+ @hybrid_property
933
+ async def username(self):return await self.bot.get_username(self.chat_id)
934
+ @hybrid_property
935
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 7.1.4
4
- Summary: rubika A Python library for interacting with Rubika Bot API.
3
+ Version: 7.1.5
4
+ Summary: Rubika: A Python library for interacting with the Rubika Bot API. This library provides an easy-to-use interface to send messages, polls, stickers, media files, manage groups and channels, handle inline keyboards, and implement advanced bot features like subscription management, user authentication, and message handling. Ideal for developers looking to automate and extend their Rubika bots with Python.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/rubka/archive/refs/tags/v6.6.4.zip
7
7
  Author: Mahdi Ahmadi
@@ -12,7 +12,7 @@ License: MIT
12
12
  Project-URL: Bug Tracker, https://t.me/Bprogrammer
13
13
  Project-URL: Documentation, https://github.com/Mahdy-Ahmadi/rubka/blob/main/README.md
14
14
  Project-URL: Source Code, https://github.com/Mahdy-Ahmadi/Rubka
15
- Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram
15
+ Keywords: rubika bot api library chat messaging rubpy pyrubi rubigram rubika_bot rubika_api fast_rub
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Programming Language :: Python :: 3
@@ -1,9 +1,9 @@
1
1
  rubka/__init__.py,sha256=P6IBiORfp-GqKHe5LZ-5lldWyG7tnrUYUcAQDUgwXmY,1973
2
- rubka/api.py,sha256=fo4X9MH_HqQmLkRNhjJcJJZOHp5lkFZqitCXs2qL_kc,68891
3
- rubka/asynco.py,sha256=QIwWgfhmKqNeqkO0VxpoLCmNBKVM58GP8JdpuvgCzL8,108338
2
+ rubka/api.py,sha256=wa1gQj7NDc7QEbmNNRz-TIOdVqfMWFC362tndRKdqig,68449
3
+ rubka/asynco.py,sha256=Zh5_oyiRH7_8xyLABREyI-Qcoy6GkybLgJqlDcR_Mm0,109869
4
4
  rubka/button.py,sha256=woSzZVd5MtTqOrP-YgkH5b0GS9y4DuKBsFSc9-KuLnk,13320
5
5
  rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
6
- rubka/context.py,sha256=-oC9h7U_H3CrtqUCDCnFXAvC7zdSmwxlc0CNwL1XLxM,34314
6
+ rubka/context.py,sha256=OowmsvqkThzB1NDhK5629Jm4ExdaWcjUo4rsBjpTtjA,38536
7
7
  rubka/decorators.py,sha256=hGwUoE4q2ImrunJIGJ_kzGYYxQf1ueE0isadqraKEts,1157
8
8
  rubka/exceptions.py,sha256=DDOGIHEMoliHNW5E7C_s38WZgqqMBv9812fcJGvj7TY,1173
9
9
  rubka/filters.py,sha256=DY1bdkpRKIiLtVcy6X3hOnlGPcVOK4HFb3QgmaPx6Oo,12116
@@ -37,8 +37,8 @@ rubka/adaptorrubka/types/socket/message.py,sha256=0WgLMZh4eow8Zn7AiSX4C3GZjQTkIg
37
37
  rubka/adaptorrubka/utils/__init__.py,sha256=OgCFkXdNFh379quNwIVOAWY2NP5cIOxU5gDRRALTk4o,54
38
38
  rubka/adaptorrubka/utils/configs.py,sha256=nMUEOJh1NqDJsf9W9PurkN_DLYjO6kKPMm923i4Jj_A,492
39
39
  rubka/adaptorrubka/utils/utils.py,sha256=5-LioLNYX_TIbQGDeT50j7Sg9nAWH2LJUUs-iEXpsUY,8816
40
- rubka-7.1.4.dist-info/METADATA,sha256=mkANXgvGnSdKVFOHBJ7cXCVEs7W5aoOZopYA4RmiU5A,34291
41
- rubka-7.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
- rubka-7.1.4.dist-info/entry_points.txt,sha256=4aESuUmuUOALMUy7Kucv_Gb5YlqhsJmTmdXLlZU9sJ0,46
43
- rubka-7.1.4.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
44
- rubka-7.1.4.dist-info/RECORD,,
40
+ rubka-7.1.5.dist-info/METADATA,sha256=a2vt5zLh2ZmkEtDUxihvZbZKAj66TaFN3PrUiiF1RjA,34667
41
+ rubka-7.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
+ rubka-7.1.5.dist-info/entry_points.txt,sha256=4aESuUmuUOALMUy7Kucv_Gb5YlqhsJmTmdXLlZU9sJ0,46
43
+ rubka-7.1.5.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
44
+ rubka-7.1.5.dist-info/RECORD,,
File without changes