Rubka 1.6.0__tar.gz → 1.7.4__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.4
2
2
  Name: Rubka
3
- Version: 1.6.0
3
+ Version: 1.7.4
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/archive/refs/tags/v0.1.0.tar.gz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 1.6.0
3
+ Version: 1.7.4
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/archive/refs/tags/v0.1.0.tar.gz
@@ -3,7 +3,7 @@ from typing import List, Optional, Dict, Any, Literal
3
3
  from .exceptions import APIRequestError
4
4
  from .logger import logger
5
5
  from typing import Callable
6
- from .context import Message
6
+ from .context import Message,InlineMessage
7
7
  API_URL = "https://botapi.rubika.ir/v3"
8
8
 
9
9
  class Robot:
@@ -17,6 +17,11 @@ class Robot:
17
17
  self._offset_id = None
18
18
  self.session = requests.Session()
19
19
  self.sessions: Dict[str, Dict[str, Any]] = {}
20
+ self._callback_handler = None
21
+ self._message_handler = None
22
+ self._inline_query_handler = None
23
+
24
+
20
25
  logger.info(f"Initialized RubikaBot with token: {token[:8]}***")
21
26
 
22
27
  def _post(self, method: str, data: Dict[str, Any]) -> Dict[str, Any]:
@@ -24,13 +29,19 @@ class Robot:
24
29
  try:
25
30
  response = self.session.post(url, json=data, timeout=10)
26
31
  response.raise_for_status()
27
- json_resp = response.json()
28
- logger.debug(f"API Response from {method}: {json_resp}")
32
+ try:
33
+ json_resp = response.json()
34
+ except ValueError:
35
+ logger.error(f"Invalid JSON response from {method}: {response.text}")
36
+ raise APIRequestError(f"Invalid JSON response: {response.text}")
37
+ if method != "getUpdates":logger.debug(f"API Response from {method}: {json_resp}")
38
+
29
39
  return json_resp
30
40
  except requests.RequestException as e:
31
41
  logger.error(f"API request failed: {e}")
32
42
  raise APIRequestError(f"API request failed: {e}") from e
33
43
 
44
+
34
45
  def get_me(self) -> Dict[str, Any]:
35
46
  """Get info about the bot itself."""
36
47
  return self._post("getMe", {})
@@ -45,21 +56,30 @@ class Robot:
45
56
  return decorator
46
57
 
47
58
 
59
+ def on_inline_query(self):
60
+ def decorator(func: Callable[[Any, InlineMessage], None]):
61
+ self._inline_query_handler = func
62
+ return func
63
+ return decorator
64
+
65
+
48
66
 
49
67
  def _process_update(self, update: Dict[str, Any]):
50
- update_data = update.get('update', {})
51
- if update_data.get('type') == 'NewMessage':
52
- msg = update_data.get('new_message', {})
53
- chat_id = update_data.get('chat_id')
68
+ if update.get('type') == 'ReceiveQuery':
69
+ msg = update.get("inline_message", {})
70
+ if self._inline_query_handler:
71
+ context = InlineMessage(bot=self, raw_data=msg)
72
+ self._inline_query_handler(self, context)
73
+ if update.get('type') == 'NewMessage':
74
+ msg = update.get('new_message', {})
75
+ chat_id = update.get('chat_id')
54
76
  message_id = msg.get('message_id')
55
77
  sender_id = msg.get('sender_id')
56
78
  text = msg.get('text')
57
79
 
58
80
  if self._message_handler:
59
81
  handler = self._message_handler
60
- context = Message(bot=self,chat_id=chat_id,message_id=message_id,sender_id=sender_id,text=text,raw_data=msg)
61
-
62
-
82
+ context = Message(bot=self, chat_id=chat_id, message_id=message_id, sender_id=sender_id, text=text, raw_data=msg)
63
83
 
64
84
  if handler["commands"]:
65
85
  if not context.text or not context.text.startswith("/"):
@@ -75,6 +95,17 @@ class Robot:
75
95
  return
76
96
 
77
97
  handler["func"](self, context)
98
+ elif update.get('type') == 'ReceiveQuery':
99
+ msg = update.get("inline_message", {})
100
+ chat_id = msg.get("chat_id")
101
+ message_id = msg.get("message_id")
102
+ sender_id = msg.get("sender_id")
103
+ text = msg.get("text")
104
+
105
+ if hasattr(self, "_callback_handler"):
106
+ context = Message(bot=self, chat_id=chat_id, message_id=message_id, sender_id=sender_id, text=text, raw_data=msg)
107
+ self._callback_handler(self, context)
108
+
78
109
 
79
110
 
80
111
 
@@ -83,15 +114,16 @@ class Robot:
83
114
  print("Bot started running...")
84
115
  while True:
85
116
  try:
86
- updates = self.get_updates(offset_id=self._offset_id, limit=10)
117
+ updates = self.get_updates(offset_id=self._offset_id, limit=2)
87
118
  if updates and updates.get('data'):
88
- for update in updates['data']:
119
+ for update in updates['data'].get('updates', []):
89
120
  self._process_update(update)
90
- self._offset_id = update.get('update_id', self._offset_id)
121
+ self._offset_id = updates['data'].get('next_offset_id', self._offset_id)
91
122
  except Exception as e:
92
123
  print(f"Error in run loop: {e}")
93
- logger.error(f"API request failed: {e}")
124
+ #logger.error(f"API request failed: {e}")
94
125
  raise APIRequestError(f"API request failed: {e}") from e
126
+
95
127
  def send_message(
96
128
  self,
97
129
  chat_id: str,
@@ -185,15 +185,18 @@ class Bot:
185
185
  self.start_message: str = data.get("start_message")
186
186
  self.share_url: str = data.get("share_url")
187
187
  class Message:
188
- def __init__(self, bot, chat_id, message_id, sender_id, text, raw_data=None):
188
+ def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
189
189
  self.bot = bot
190
190
  self.chat_id = chat_id
191
- self.message_id = message_id
192
- self.sender_id = sender_id
193
- self.text = text
194
- self.args = []
195
191
  self.raw_data = raw_data or {}
192
+ self.message_id: str = self.raw_data.get("message_id", message_id)
193
+ self.text: str = self.raw_data.get("text", text)
194
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
195
+ self.time: str = self.raw_data.get("time")
196
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
197
+ self.sender_type: str = self.raw_data.get("sender_type")
196
198
 
199
+ self.args = []
197
200
  self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
198
201
  self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
199
202
  self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
@@ -292,3 +295,34 @@ class Message:
292
295
  chat_id=self.chat_id,
293
296
  message_id=self.message_id
294
297
  )
298
+ class InlineMessage:
299
+ def __init__(self, bot, raw_data: dict):
300
+ self.bot = bot
301
+ self.raw_data = raw_data
302
+
303
+ self.chat_id: str = raw_data.get("chat_id")
304
+ self.message_id: str = raw_data.get("message_id")
305
+ self.sender_id: str = raw_data.get("sender_id")
306
+ self.text: str = raw_data.get("text")
307
+ self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
308
+
309
+ def reply(self, text: str, **kwargs):
310
+ return self.bot.send_message(
311
+ chat_id=self.chat_id,
312
+ text=text,
313
+ reply_to_message_id=self.message_id,
314
+ **kwargs
315
+ )
316
+
317
+ def edit(self, new_text: str):
318
+ return self.bot.edit_message_text(
319
+ chat_id=self.chat_id,
320
+ message_id=self.message_id,
321
+ text=new_text
322
+ )
323
+
324
+ def delete(self):
325
+ return self.bot.delete_message(
326
+ chat_id=self.chat_id,
327
+ message_id=self.message_id
328
+ )
@@ -0,0 +1,48 @@
1
+ from typing import Dict
2
+
3
+ class InlineBuilder:
4
+ def __init__(self):
5
+ self.rows = []
6
+
7
+ def row(self, *buttons: Dict[str, str]):
8
+ self.rows.append({"buttons": list(buttons)})
9
+ return self
10
+
11
+ def button(self, id: str, text: str, type: str = "Simple") -> Dict[str, str]:
12
+ return {"id": id, "type": type, "button_text": text}
13
+
14
+ def build(self):
15
+ return {"rows": self.rows}
16
+ from typing import List, Dict, Optional
17
+
18
+ class ChatKeypadBuilder:
19
+ def __init__(self):
20
+ self.rows: List[Dict[str, List[Dict[str, str]]]] = []
21
+
22
+ def row(self, *buttons: Dict[str, str]) -> "ChatKeypadBuilder":
23
+ """
24
+ یک ردیف دکمه به کی‌پد اضافه می‌کند.
25
+ ورودی: چند دیکشنری که نماینده دکمه‌ها هستند.
26
+ """
27
+ self.rows.append({"buttons": list(buttons)})
28
+ return self
29
+
30
+ def button(self, id: str, text: str, type: str = "Simple") -> Dict[str, str]:
31
+ """
32
+ دیکشنری یک دکمه می‌سازد.
33
+ """
34
+ return {"id": id, "type": type, "button_text": text}
35
+
36
+ def build(
37
+ self,
38
+ resize_keyboard: bool = True,
39
+ on_time_keyboard: bool = False
40
+ ) -> Dict[str, object]:
41
+ """
42
+ ساختار نهایی chat_keypad را می‌سازد.
43
+ """
44
+ return {
45
+ "rows": self.rows,
46
+ "resize_keyboard": resize_keyboard,
47
+ "on_time_keyboard": on_time_keyboard
48
+ }
@@ -1,10 +1,10 @@
1
1
  import logging
2
2
 
3
3
  logger = logging.getLogger("rubka")
4
- logger.setLevel(logging.DEBUG)
4
+ logger.setLevel(logging.ERROR)
5
5
 
6
6
  ch = logging.StreamHandler()
7
- ch.setLevel(logging.DEBUG)
7
+ ch.setLevel(logging.ERROR)
8
8
 
9
9
  formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
10
10
  ch.setFormatter(formatter)
@@ -8,7 +8,7 @@ except FileNotFoundError:
8
8
 
9
9
  setup(
10
10
  name='Rubka',
11
- version='1.6.0',
11
+ version='1.7.4',
12
12
  description='A Python library for interacting with Rubika Bot API.',
13
13
  long_description=long_description,
14
14
  long_description_content_type='text/markdown',
@@ -1,15 +0,0 @@
1
- from typing import Dict
2
-
3
- class InlineBuilder:
4
- def __init__(self):
5
- self.rows = []
6
-
7
- def row(self, *buttons: Dict[str, str]):
8
- self.rows.append({"buttons": list(buttons)})
9
- return self
10
-
11
- def button(self, id: str, text: str, type: str = "Simple") -> Dict[str, str]:
12
- return {"id": id, "type": type, "button_text": text}
13
-
14
- def build(self):
15
- return {"rows": self.rows}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes