RubigramClient 1.6.6__py3-none-any.whl → 1.6.7__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 RubigramClient might be problematic. Click here for more details.

rubigram/client.py CHANGED
@@ -1,15 +1,22 @@
1
- from typing import Optional, Callable, Literal, Union
1
+ from typing import Optional, Callable, Union
2
2
  from rubigram.types import Update, InlineMessage
3
3
  from rubigram.method import Method
4
4
  from rubigram.filters import Filter
5
5
  from rubigram.state import StateManager
6
6
  from datetime import datetime
7
- from aiohttp import web
7
+ from aiohttp.web import Application, Request, json_response, run_app
8
8
  import asyncio
9
9
  import logging
10
10
 
11
11
 
12
- logging.basicConfig(format=("%(levelname)s | %(message)s"))
12
+ logging.basicConfig(
13
+ format="%(asctime)s | %(levelname)s : %(message)s",
14
+ datefmt="%Y-%m-%d %H:%M:%S",
15
+ level=logging.DEBUG
16
+ )
17
+
18
+ logging.getLogger("asyncio").setLevel(logging.WARNING)
19
+ logging.getLogger("aiohttp").setLevel(logging.WARNING)
13
20
 
14
21
 
15
22
  class Client(Method):
@@ -25,106 +32,129 @@ class Client(Method):
25
32
  self.host = host
26
33
  self.port = port
27
34
  self.offset_id = None
35
+ self.set_endpoint = True
28
36
  self.ROUTES = []
29
37
  self.MESSAGE_HANDLER = []
30
38
  self.INLINE_HANDLER = []
31
39
  self.state = StateManager()
32
- super().__init__(token)
33
-
34
-
35
- def create_handler(self, type: Literal["message", "inline"], filters: Optional[Filter] = None):
40
+ super().__init__(token)
41
+
42
+
43
+ def on_message(self, filters: Optional[Filter] = None):
36
44
  def decorator(func: Callable) -> Callable:
37
45
  async def wrapper(client: Client, update: Update):
38
46
  if filters is None or await filters(update):
39
47
  await func(client, update)
40
48
  return True
41
49
  return False
42
- self.MESSAGE_HANDLER.append(wrapper) if type == "message" else self.INLINE_HANDLER.append(wrapper)
50
+ self.MESSAGE_HANDLER.append(wrapper)
43
51
  return func
44
52
  return decorator
45
-
46
- def on_message(self, filters: Optional[Filter] = None):
47
- return self.create_handler("message", filters)
48
53
 
49
54
  def on_inline_message(self, filters: Optional[Filter] = None):
50
- return self.create_handler("inline", filters)
51
-
52
- async def dispatch(self, update: Union[Update, InlineMessage], type: Literal["message", "inline"]):
53
- handlers = self.MESSAGE_HANDLER if type == "message" else self.INLINE_HANDLER
55
+ def decorator(func: Callable) -> Callable:
56
+ async def wrapper(client: Client, update: Update):
57
+ if filters is None or await filters(update):
58
+ await func(client, update)
59
+ return True
60
+ return False
61
+ self.INLINE_HANDLER.append(wrapper)
62
+ return func
63
+ return decorator
64
+
65
+ def on_create_app(self, path: str, method: str = "GET"):
66
+ def decorator(func):
67
+ self.ROUTES.append((path, func, method.upper()))
68
+ return func
69
+ return decorator
70
+
71
+ async def dispatch(self, update: Union[Update, InlineMessage]):
72
+ handlers = self.MESSAGE_HANDLER if isinstance(update, Update) else self.INLINE_HANDLER
54
73
  for handler in handlers:
55
74
  matched = await handler(self, update)
56
75
  if matched:
57
76
  return
58
-
77
+
59
78
  async def updater(self, data: dict):
60
79
  if "inline_message" in data:
61
80
  event = InlineMessage.from_dict(data["inline_message"])
62
- type = "inline"
63
81
  elif "update" in data:
64
82
  event = Update.from_dict(data["update"])
65
- type = "message"
66
83
  else: return
67
84
  event.client = self
68
- await self.dispatch(event, type)
69
-
85
+ await self.dispatch(event)
86
+
70
87
  async def set_endpoints(self):
71
88
  endpoint_type = ["ReceiveUpdate", "ReceiveInlineMessage"]
72
- for i in endpoint_type: await self.update_bot_endpoint(f"{self.endpoint}/{i}", i)
73
-
89
+ for i in endpoint_type:
90
+ set_endpoint = await self.update_bot_endpoint(f"{self.endpoint}/{i}", i)
91
+ logging.info(f"status set endpoint for {i} : {set_endpoint["status"]}")
92
+
74
93
  async def on_startup(self, app):
75
- await self.set_endpoints()
94
+ if self.set_endpoint:
95
+ await self.set_endpoints()
76
96
  await self.start()
77
97
 
78
98
  async def on_cleanup(self, app):
79
99
  await self.stop()
80
100
 
81
101
  def create_request_handler(self):
82
- async def wrapper(request: web.Request):
102
+ async def wrapper(request: Request):
83
103
  data = await request.json()
84
104
  await self.updater(data)
85
- return web.json_response({"status": "OK"})
105
+ return json_response({"status": "OK"})
86
106
  return wrapper
87
-
88
- async def runner(self):
107
+
108
+
109
+ async def update_runner(self):
89
110
  try:
90
111
  while True:
91
- get_updates = await self.get_update(100, self.offset_id)
92
- if get_updates.updates:
93
- updates = get_updates.updates
112
+ get_update = await self.get_update(100, self.offset_id)
113
+ updates = get_update.updates
114
+ if updates:
94
115
  for update in updates:
95
- time = int(update.new_message.time) if update.type == "NewMessage" else int(update.updated_message.time) if update.type == "UpdatedMessage" else None
116
+ time = update.new_message.time if update.type == "NewMessage" else update.updated_message.time if update.type == "UpdatedMessage" else None
117
+ time = int(time)
96
118
  now = int(datetime.now().timestamp())
97
- if time and time >= now or time + 2 >= now:
119
+ if time and (time >= now or time + 2 >= now):
98
120
  update.client = self
99
- await self.dispatch(update, "message")
100
- self.offset_id = get_updates.next_offset_id
121
+ await self.dispatch(update)
122
+ self.offset_id = get_update.next_offset_id
101
123
  except Exception as error:
102
124
  logging.error(error)
103
125
  finally:
104
126
  await self.stop()
105
127
 
106
- def create_app(self, path: str, method: str = "Get"):
107
- def decorator(func):
108
- self.ROUTES.append((path, func, method))
109
- return func
110
- return decorator
111
-
112
- def run(self):
128
+ def run(self, set_endpoint = True):
129
+ self.set_endpoint = set_endpoint
113
130
  if self.endpoint:
114
- app = web.Application()
131
+ app = Application()
115
132
  app.on_startup(self.on_startup)
116
133
  app.on_cleanup(self.on_cleanup)
117
- for path, func, method in self.ROUTES:
118
- if method.upper() == "GET":
119
- app.router.add_get(path, func)
120
- elif method.upper() == "POST":
121
- app.router.add_post(path, func)
134
+
122
135
  app.router.add_post("/ReceiveUpdate", self.create_request_handler())
123
136
  app.router.add_post("/ReceiveInlineMessage", self.create_request_handler())
124
- web.run_app(app, host=self.host, port=self.port)
137
+
138
+ for path, func, method in self.ROUTES:
139
+ match method:
140
+ case "GET":
141
+ app.router.add_get(path, func)
142
+ case "POST":
143
+ app.router.add_post(path, func)
144
+ case "DELETE":
145
+ app.router.add_delete(path, func)
146
+ case "PUT":
147
+ app.router.add_put(path, func)
148
+ case "PATCH":
149
+ app.router.add_patch(path, func)
150
+
151
+ run_app(app, host=self.host, port=self.port)
152
+
125
153
  else:
126
154
  try:
127
- asyncio.run(self.runner())
128
- except KeyboardInterrupt:pass
155
+ logging.info("Start Bot")
156
+ asyncio.run(self.update_runner())
157
+ except KeyboardInterrupt:
158
+ logging.info("Stop Bot")
129
159
  except Exception as error:
130
160
  logging.error(error)
rubigram/method.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from .network import Network
2
2
  from rubigram import enums
3
- from typing import Optional
3
+ from typing import Optional, Union
4
4
  from rubigram.types import Bot, Chat, Keypad, MessageId, Updates, BotCommand
5
5
 
6
6
 
@@ -195,30 +195,31 @@ class Method(Network):
195
195
  response = await self.request("requestSendFile", {"type": type})
196
196
  return response["upload_url"]
197
197
 
198
- async def upload_file(self, file: str, name: str, type: str):
198
+ async def upload_file(self, file: Union[str, bytes], name: Optional[str] = None, type: str = "File"):
199
199
  upload_url = await self.request_send_file(type)
200
- response = await self.RequestUploadFile(upload_url, file, name)
200
+ response = await self.requestUpload(upload_url, file, name)
201
201
  return response
202
202
 
203
- async def download_file(self, file_id: str, file_name: str):
203
+ async def download_file(self, file_id: str, filename: Optional[str] = None):
204
204
  download_url = await self.get_file(file_id)
205
- response = await self.RequestDownloadFile(download_url, file_name)
205
+ response = await self.requestDownload(download_url, filename)
206
206
  return response
207
207
 
208
208
  async def send_file(
209
209
  self,
210
210
  chat_id: str,
211
- file: str,
212
- file_name: str,
213
- caption: str = None,
211
+ file: Union[str, bytes],
212
+ caption: Optional[str] = None,
213
+ file_name: Optional[str] = None,
214
214
  type: enums.FileType = enums.FileType.File,
215
215
  chat_keypad: Keypad = None,
216
216
  inline_keypad: Keypad = None,
217
217
  chat_keypad_type: Optional[enums.ChatKeypadType] = None,
218
218
  disable_notification: bool = False,
219
- reply_to_message_id: str = None,
219
+ reply_to_message_id: Optional[str] = None,
220
220
  ) -> "MessageId":
221
221
  file_id = await self.upload_file(file, file_name, type)
222
+
222
223
  data = {
223
224
  "chat_id": chat_id,
224
225
  "file_id": file_id,
@@ -236,20 +237,22 @@ class Method(Network):
236
237
  message.client = self
237
238
  return message
238
239
 
239
- async def send_document(self, chat_id: str, document: str, name: str, caption: str = None, **kwargs):
240
- return await self.send_file(chat_id, document, name, caption, "File", **kwargs)
241
240
 
242
- async def send_photo(self, chat_id: str, photo: str, name: str, caption: str = None, **kwargs):
243
- return await self.send_file(chat_id, photo, name, caption, "Image", **kwargs)
244
241
 
245
- async def send_video(self, chat_id: str, video: str, name: str, caption: str = None, **kwargs):
246
- return await self.send_file(chat_id, video, name, caption, "Video", **kwargs)
242
+ async def send_document(self, chat_id: str, document: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
243
+ return await self.send_file(chat_id, document, caption, file_name, "File", **kwargs)
244
+
245
+ async def send_photo(self, chat_id: str, photo: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
246
+ return await self.send_file(chat_id, photo, caption, file_name, "Image", **kwargs)
247
+
248
+ async def send_video(self, chat_id: str, video: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
249
+ return await self.send_file(chat_id, video, caption, file_name, "Video", **kwargs)
247
250
 
248
- async def send_gif(self, chat_id: str, gif: str, name: str, caption: str = None, **kwargs):
249
- return await self.send_file(chat_id, gif, name, caption, "Gif", **kwargs)
251
+ async def send_gif(self, chat_id: str, gif: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
252
+ return await self.send_file(chat_id, gif, caption, file_name, "Gif", **kwargs)
250
253
 
251
- async def send_music(self, chat_id: str, music: str, name: str, caption: str = None, **kwargs):
252
- return await self.send_file(chat_id, music, name, caption, "Music", **kwargs)
254
+ async def send_music(self, chat_id: str, music: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
255
+ return await self.send_file(chat_id, music, caption, file_name, "Music", **kwargs)
253
256
 
254
- async def send_voice(self, chat_id: str, voice: str, name: str, caption: str = None, **kwargs):
255
- return await self.send_file(chat_id, voice, name, caption, "Voice", **kwargs)
257
+ async def send_voice(self, chat_id: str, voice: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs):
258
+ return await self.send_file(chat_id, voice, caption, file_name, "Voice", **kwargs)
rubigram/network.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from aiohttp import ClientSession, FormData
2
- from typing import Any, Optional
3
- import aiofiles, re, os
2
+ from typing import Any, Optional, Union
3
+ from pathlib import Path
4
+ from urllib.parse import urlparse
5
+ import aiofiles
6
+ import os
4
7
 
5
8
 
6
9
  class Network:
@@ -32,34 +35,46 @@ class Network:
32
35
  data: dict = await response.json()
33
36
  return data.get("data")
34
37
 
35
- async def ContentFile(self, url: str) -> bytes:
38
+ async def getBytes(self, url: str) -> bytes:
36
39
  await self.start()
37
40
  async with self.session.get(url) as response:
38
41
  response.raise_for_status()
39
42
  return await response.read()
40
43
 
41
- async def RequestUploadFile(self, upload_url: str, file: str, name: str):
44
+ async def getName(self, url: str) -> str:
45
+ parser = urlparse(url)
46
+ return os.path.basename(parser.path)
47
+
48
+ async def requestUpload(self, upload_url: str, file: Union[str, bytes], name: Optional[str] = None):
49
+ data, filename = None, None
42
50
  if isinstance(file, str):
43
- if re.match(r"^https://", file):
44
- file = await self.ContentFile(file)
45
- elif os.path.isfile(file):
46
- async with aiofiles.open(file, "rb") as f:
47
- file = await f.read()
48
- else:
49
- raise Exception("file not found : {}".format(file))
51
+ path = Path(file)
52
+
53
+ if path.is_file():
54
+ data, filename = path.read_bytes(), name if name else path.name
50
55
 
51
- form = FormData()
52
- form.add_field("file", file, filename=name, content_type="application/octet-stream")
53
- await self.start()
54
- async with self.session.post(upload_url, data=form) as response:
55
- response.raise_for_status()
56
- data: dict = await response.json()
57
- return data.get("data", {}).get("file_id")
56
+ elif file.startswith("http"):
57
+ data, filename = await self.getBytes(file), name if name else await self.getName(file)
58
+
59
+ else:
60
+ raise Exception(f"Can't find this file : {file}")
58
61
 
59
- raise Exception("Format Of file is invalid")
62
+ elif isinstance(file, bytes):
63
+ if name:
64
+ data, filename = file, name
65
+ else:
66
+ raise Exception("choice name for bytes file")
67
+
68
+ form = FormData()
69
+ form.add_field("file", data, filename=filename, content_type="application/octet-stream")
70
+ await self.start()
71
+ async with self.session.post(upload_url, data=form) as response:
72
+ response.raise_for_status()
73
+ data: dict = await response.json()
74
+ return data.get("data", {})["file_id"]
60
75
 
61
- async def RequestDownloadFile(self, url: str, name: str):
62
- file = await self.ContentFile(url)
76
+ async def requestDownload(self, url: str, filename: Optional[str] = None):
77
+ file, name = await self.getBytes(url), filename if filename else await self.getName(url)
63
78
  async with aiofiles.open(name, "wb") as f:
64
79
  await f.write(file)
65
- return name
80
+ return name
rubigram/types.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Optional, Any
1
+ from typing import Optional, Union, Any
2
2
  from pydantic import BaseModel
3
3
  from rubigram import enums
4
4
 
@@ -28,12 +28,48 @@ class Chat(DataManager):
28
28
  title: Optional[str] = None
29
29
  username: Optional[str] = None
30
30
 
31
+ def __init__(
32
+ self,
33
+ chat_id: Optional[str] = None,
34
+ chat_type: Optional[enums.ChatType] = None,
35
+ user_id: Optional[str] = None,
36
+ first_name: Optional[str] = None,
37
+ last_name: Optional[str] = None,
38
+ title: Optional[str] = None,
39
+ username: Optional[str] = None,
40
+ **kwargs
41
+ ):
42
+ super().__init__(
43
+ chat_id=chat_id,
44
+ chat_type=chat_type,
45
+ user_id=user_id,
46
+ first_name=first_name,
47
+ last_name=last_name,
48
+ title=title,
49
+ username=username,
50
+ **kwargs
51
+ )
52
+
31
53
 
32
54
  class File(DataManager):
33
55
  file_id: Optional[str] = None
34
56
  file_name: Optional[str] = None
35
57
  size: Optional[str] = None
36
58
 
59
+ def __init__(
60
+ self,
61
+ file_id: Optional[str] = None,
62
+ file_name: Optional[str] = None,
63
+ size: Optional[str] = None,
64
+ **kwargs
65
+ ):
66
+ super().__init__(
67
+ file_id=file_id,
68
+ file_name=file_name,
69
+ size=size,
70
+ **kwargs
71
+ )
72
+
37
73
 
38
74
  class ForwardedFrom(DataManager):
39
75
  type_from: Optional[enums.ForwardedFrom] = None
@@ -41,16 +77,56 @@ class ForwardedFrom(DataManager):
41
77
  from_chat_id: Optional[str] = None
42
78
  from_sender_id: Optional[str] = None
43
79
 
80
+ def __init__(
81
+ self,
82
+ type_from: Optional[enums.ForwardedFrom] = None,
83
+ message_id: Optional[str] = None,
84
+ from_chat_id: Optional[str] = None,
85
+ from_sender_id: Optional[str] = None,
86
+ **kwargs
87
+ ):
88
+ super().__init__(
89
+ type_from=type_from,
90
+ message_id=message_id,
91
+ from_chat_id=from_chat_id,
92
+ from_sender_id=from_sender_id,
93
+ **kwargs
94
+ )
95
+
44
96
 
45
97
  class PaymentStatus(DataManager):
46
98
  payment_id: Optional[str] = None
47
99
  status: Optional[enums.PaymentStatus] = None
48
100
 
101
+ def __init__(
102
+ self,
103
+ payment_id: Optional[str] = None,
104
+ status: Optional[enums.PaymentStatus] = None,
105
+ **kwargs
106
+ ):
107
+ super().__init__(
108
+ payment_id=payment_id,
109
+ status=status,
110
+ **kwargs
111
+ )
112
+
49
113
 
50
114
  class MessageTextUpdate(DataManager):
51
115
  message_id: Optional[str] = None
52
116
  text: Optional[str] = None
53
117
 
118
+ def __init__(
119
+ self,
120
+ message_id: Optional[str] = None,
121
+ text: Optional[str] = None,
122
+ **kwargs
123
+ ):
124
+ super().__init__(
125
+ message_id=message_id,
126
+ text=text,
127
+ **kwargs
128
+ )
129
+
54
130
 
55
131
  class Bot(DataManager):
56
132
  bot_id: Optional[str] = None
@@ -61,23 +137,85 @@ class Bot(DataManager):
61
137
  start_message: Optional[str] = None
62
138
  share_url: Optional[str] = None
63
139
 
140
+ def __init__(
141
+ self,
142
+ bot_id: Optional[str] = None,
143
+ bot_title: Optional[str] = None,
144
+ avatar: Optional[File] = None,
145
+ description: Optional[str] = None,
146
+ username: Optional[str] = None,
147
+ start_message: Optional[str] = None,
148
+ share_url: Optional[str] = None,
149
+ **kwargs
150
+ ):
151
+ super().__init__(
152
+ bot_id=bot_id,
153
+ bot_title=bot_title,
154
+ avatar=avatar,
155
+ description=description,
156
+ username=username,
157
+ start_message=start_message,
158
+ share_url=share_url,
159
+ **kwargs
160
+ )
161
+
64
162
 
65
163
  class BotCommand(DataManager):
66
164
  command: Optional[str] = None
67
165
  description: Optional[str] = None
68
166
 
167
+ def __init__(
168
+ self,
169
+ command: Optional[str] = None,
170
+ description: Optional[str] = None,
171
+ **kwargs
172
+ ):
173
+ super().__init__(
174
+ command=command,
175
+ description=description,
176
+ **kwargs
177
+ )
178
+
69
179
 
70
180
  class Sticker(DataManager):
71
181
  sticker_id: Optional[str] = None
72
182
  file: Optional[File] = None
73
183
  emoji_character: Optional[str] = None
74
184
 
185
+ def __init__(
186
+ self,
187
+ sticker_id: Optional[str] = None,
188
+ file: Optional[File] = None,
189
+ emoji_character: Optional[str] = None,
190
+ **kwargs
191
+ ):
192
+ super().__init__(
193
+ sticker_id=sticker_id,
194
+ file=file,
195
+ emoji_character=emoji_character,
196
+ **kwargs
197
+ )
198
+
75
199
 
76
200
  class ContactMessage(DataManager):
77
201
  phone_number: Optional[str] = None
78
202
  first_name: Optional[str] = None
79
203
  last_name: Optional[str] = None
80
204
 
205
+ def __init__(
206
+ self,
207
+ phone_number: Optional[str] = None,
208
+ first_name: Optional[str] = None,
209
+ last_name: Optional[str] = None,
210
+ **kwargs
211
+ ):
212
+ super().__init__(
213
+ phone_number=phone_number,
214
+ first_name=first_name,
215
+ last_name=last_name,
216
+ **kwargs
217
+ )
218
+
81
219
 
82
220
  class PollStatus(DataManager):
83
221
  state: Optional[enums.PollStatus] = None
@@ -86,17 +224,61 @@ class PollStatus(DataManager):
86
224
  total_vote: Optional[int] = None
87
225
  show_total_votes: Optional[bool] = None
88
226
 
227
+ def __init__(
228
+ self,
229
+ state: Optional[enums.PollStatus] = None,
230
+ selection_index: Optional[int] = None,
231
+ percent_vote_options: Optional[list[int]] = None,
232
+ total_vote: Optional[int] = None,
233
+ show_total_votes: Optional[bool] = None,
234
+ **kwargs
235
+ ):
236
+ super().__init__(
237
+ state=state,
238
+ selection_index=selection_index,
239
+ percent_vote_options=percent_vote_options,
240
+ total_vote=total_vote,
241
+ show_total_votes=show_total_votes,
242
+ **kwargs
243
+ )
244
+
89
245
 
90
246
  class Poll(DataManager):
91
247
  question: Optional[str] = None
92
248
  options: Optional[list[str]] = None
93
249
  poll_status: Optional[PollStatus] = None
94
250
 
251
+ def __init__(
252
+ self,
253
+ question: Optional[str] = None,
254
+ options: Optional[list[str]] = None,
255
+ poll_status: Optional[PollStatus] = None,
256
+ **kwargs
257
+ ):
258
+ super().__init__(
259
+ question=question,
260
+ options=options,
261
+ poll_status=poll_status,
262
+ **kwargs
263
+ )
264
+
95
265
 
96
266
  class Location(DataManager):
97
267
  longitude: Optional[str] = None
98
268
  latitude: Optional[str] = None
99
269
 
270
+ def __init__(
271
+ self,
272
+ longitude: Optional[str] = None,
273
+ latitude: Optional[str] = None,
274
+ **kwargs
275
+ ):
276
+ super().__init__(
277
+ longitude=longitude,
278
+ latitude=latitude,
279
+ **kwargs
280
+ )
281
+
100
282
 
101
283
  class LiveLocation(DataManager):
102
284
  start_time: Optional[str] = None
@@ -106,12 +288,46 @@ class LiveLocation(DataManager):
106
288
  status: Optional[enums.LiveLocationStatus] = None
107
289
  last_update_time: Optional[str] = None
108
290
 
291
+ def __init__(
292
+ self,
293
+ start_time: Optional[str] = None,
294
+ live_period: Optional[int] = None,
295
+ current_location: Optional[Location] = None,
296
+ user_id: Optional[str] = None,
297
+ status: Optional[enums.LiveLocationStatus] = None,
298
+ last_update_time: Optional[str] = None,
299
+ **kwargs
300
+ ):
301
+ super().__init__(
302
+ start_time=start_time,
303
+ live_period=live_period,
304
+ current_location=current_location,
305
+ user_id=user_id,
306
+ status=status,
307
+ last_update_time=last_update_time,
308
+ **kwargs
309
+ )
310
+
109
311
 
110
312
  class ButtonSelectionItem(DataManager):
111
313
  text: Optional[str] = None
112
314
  image_url: Optional[str] = None
113
315
  type: Optional[enums.ButtonSelectionType] = None
114
316
 
317
+ def __init__(
318
+ self,
319
+ text: Optional[str] = None,
320
+ image_url: Optional[str] = None,
321
+ type: Optional[enums.ButtonSelectionType] = None,
322
+ **kwargs
323
+ ):
324
+ super().__init__(
325
+ text=text,
326
+ image_url=image_url,
327
+ type=type,
328
+ **kwargs
329
+ )
330
+
115
331
 
116
332
  class ButtonSelection(DataManager):
117
333
  selection_id: Optional[str] = None
@@ -122,6 +338,28 @@ class ButtonSelection(DataManager):
122
338
  columns_count: Optional[str] = None
123
339
  title: Optional[str] = None
124
340
 
341
+ def __init__(
342
+ self,
343
+ selection_id: Optional[str] = None,
344
+ search_type: Optional[str] = None,
345
+ get_type: Optional[str] = None,
346
+ items: Optional[list[ButtonSelectionItem]] = None,
347
+ is_multi_selection: Optional[bool] = None,
348
+ columns_count: Optional[str] = None,
349
+ title: Optional[str] = None,
350
+ **kwargs
351
+ ):
352
+ super().__init__(
353
+ selection_id=selection_id,
354
+ search_type=search_type,
355
+ get_type=get_type,
356
+ items=items,
357
+ is_multi_selection=is_multi_selection,
358
+ columns_count=columns_count,
359
+ title=title,
360
+ **kwargs
361
+ )
362
+
125
363
 
126
364
  class ButtonCalendar(DataManager):
127
365
  default_value: Optional[str] = None
@@ -130,6 +368,24 @@ class ButtonCalendar(DataManager):
130
368
  max_year: Optional[str] = None
131
369
  title: Optional[str] = None
132
370
 
371
+ def __init__(
372
+ self,
373
+ default_value: Optional[str] = None,
374
+ type: Optional[enums.ButtonCalendarType] = None,
375
+ min_year: Optional[str] = None,
376
+ max_year: Optional[str] = None,
377
+ title: Optional[str] = None,
378
+ **kwargs
379
+ ):
380
+ super().__init__(
381
+ default_value=default_value,
382
+ type=type,
383
+ min_year=min_year,
384
+ max_year=max_year,
385
+ title=title,
386
+ **kwargs
387
+ )
388
+
133
389
 
134
390
  class ButtonNumberPicker(DataManager):
135
391
  min_value: Optional[str] = None
@@ -137,12 +393,42 @@ class ButtonNumberPicker(DataManager):
137
393
  default_value: Optional[str] = None
138
394
  title: Optional[str] = None
139
395
 
396
+ def __init__(
397
+ self,
398
+ min_value: Optional[str] = None,
399
+ max_value: Optional[str] = None,
400
+ default_value: Optional[str] = None,
401
+ title: Optional[str] = None,
402
+ **kwargs
403
+ ):
404
+ super().__init__(
405
+ min_value=min_value,
406
+ max_value=max_value,
407
+ default_value=default_value,
408
+ title=title,
409
+ **kwargs
410
+ )
411
+
140
412
 
141
413
  class ButtonStringPicker(DataManager):
142
414
  items: Optional[list[str]] = None
143
415
  default_value: Optional[str] = None
144
416
  title: Optional[str] = None
145
417
 
418
+ def __init__(
419
+ self,
420
+ items: Optional[list[str]] = None,
421
+ default_value: Optional[str] = None,
422
+ title: Optional[str] = None,
423
+ **kwargs
424
+ ):
425
+ super().__init__(
426
+ items=items,
427
+ default_value=default_value,
428
+ title=title,
429
+ **kwargs
430
+ )
431
+
146
432
 
147
433
  class ButtonTextbox(DataManager):
148
434
  type_line: Optional[enums.ButtonTextboxTypeLine] = None
@@ -151,6 +437,24 @@ class ButtonTextbox(DataManager):
151
437
  title: Optional[str] = None
152
438
  default_value: Optional[str] = None
153
439
 
440
+ def __init__(
441
+ self,
442
+ type_line: Optional[enums.ButtonTextboxTypeLine] = None,
443
+ type_keypad: Optional[enums.ButtonTextboxTypeKeypad] = None,
444
+ place_holder: Optional[str] = None,
445
+ title: Optional[str] = None,
446
+ default_value: Optional[str] = None,
447
+ **kwargs
448
+ ):
449
+ super().__init__(
450
+ type_line=type_line,
451
+ type_keypad=type_keypad,
452
+ place_holder=place_holder,
453
+ title=title,
454
+ default_value=default_value,
455
+ **kwargs
456
+ )
457
+
154
458
 
155
459
  class ButtonLocation(DataManager):
156
460
  default_pointer_location: Optional[Location] = None
@@ -159,16 +463,58 @@ class ButtonLocation(DataManager):
159
463
  title: Optional[str] = None
160
464
  location_image_url: Optional[str] = None
161
465
 
466
+ def __init__(
467
+ self,
468
+ default_pointer_location: Optional[Location] = None,
469
+ default_map_location: Optional[Location] = None,
470
+ type: Optional[enums.ButtonLocationType] = None,
471
+ title: Optional[str] = None,
472
+ location_image_url: Optional[str] = None,
473
+ **kwargs
474
+ ):
475
+ super().__init__(
476
+ default_pointer_location=default_pointer_location,
477
+ default_map_location=default_map_location,
478
+ type=type,
479
+ title=title,
480
+ location_image_url=location_image_url,
481
+ **kwargs
482
+ )
483
+
162
484
 
163
485
  class OpenChatData(DataManager):
164
486
  object_guid: Optional[str] = None
165
487
  object_type: Optional[enums.ChatType] = None
166
488
 
489
+ def __init__(
490
+ self,
491
+ object_guid: Optional[str] = None,
492
+ object_type: Optional[enums.ChatType] = None,
493
+ **kwargs
494
+ ):
495
+ super().__init__(
496
+ object_guid=object_guid,
497
+ object_type=object_type,
498
+ **kwargs
499
+ )
500
+
167
501
 
168
502
  class JoinChannelData(DataManager):
169
503
  username: Optional[str] = None
170
504
  ask_join: bool = False
171
505
 
506
+ def __init__(
507
+ self,
508
+ username: Optional[str] = None,
509
+ ask_join: bool = False,
510
+ **kwargs
511
+ ):
512
+ super().__init__(
513
+ username=username,
514
+ ask_join=ask_join,
515
+ **kwargs
516
+ )
517
+
172
518
 
173
519
  class ButtonLink(DataManager):
174
520
  type: Optional[enums.ButtonLinkType] = None
@@ -176,11 +522,39 @@ class ButtonLink(DataManager):
176
522
  joinchannel_data: Optional[JoinChannelData] = None
177
523
  open_chat_data: Optional[OpenChatData] = None
178
524
 
525
+ def __init__(
526
+ self,
527
+ type: Optional[enums.ButtonLinkType] = None,
528
+ link_url: Optional[str] = None,
529
+ joinchannel_data: Optional[JoinChannelData] = None,
530
+ open_chat_data: Optional[OpenChatData] = None,
531
+ **kwargs
532
+ ):
533
+ super().__init__(
534
+ type=type,
535
+ link_url=link_url,
536
+ joinchannel_data=joinchannel_data,
537
+ open_chat_data=open_chat_data,
538
+ **kwargs
539
+ )
540
+
179
541
 
180
542
  class AuxData(DataManager):
181
543
  start_id: Optional[str] = None
182
544
  button_id: Optional[str] = None
183
545
 
546
+ def __init__(
547
+ self,
548
+ start_id: Optional[str] = None,
549
+ button_id: Optional[str] = None,
550
+ **kwargs
551
+ ):
552
+ super().__init__(
553
+ start_id=start_id,
554
+ button_id=button_id,
555
+ **kwargs
556
+ )
557
+
184
558
 
185
559
  class Button(DataManager):
186
560
  id: Optional[str] = None
@@ -194,21 +568,85 @@ class Button(DataManager):
194
568
  button_textbox: Optional[ButtonTextbox] = None
195
569
  button_link: Optional[ButtonLink] = None
196
570
 
571
+ def __init__(
572
+ self,
573
+ id: Optional[str] = None,
574
+ button_text: Optional[str] = None,
575
+ type: enums.ButtonType = enums.ButtonType.Simple,
576
+ button_selection: Optional[ButtonSelection] = None,
577
+ button_calendar: Optional[ButtonCalendar] = None,
578
+ button_number_picker: Optional[ButtonNumberPicker] = None,
579
+ button_string_picker: Optional[ButtonStringPicker] = None,
580
+ button_location: Optional[ButtonLocation] = None,
581
+ button_textbox: Optional[ButtonTextbox] = None,
582
+ button_link: Optional[ButtonLink] = None,
583
+ **kwargs
584
+ ):
585
+ super().__init__(
586
+ id=id,
587
+ button_text=button_text,
588
+ type=type,
589
+ button_selection=button_selection,
590
+ button_calendar=button_calendar,
591
+ button_number_picker=button_number_picker,
592
+ button_string_picker=button_string_picker,
593
+ button_location=button_location,
594
+ button_textbox=button_textbox,
595
+ button_link=button_link,
596
+ **kwargs
597
+ )
598
+
197
599
 
198
600
  class KeypadRow(DataManager):
199
601
  buttons: list[Button]
200
602
 
603
+ def __init__(
604
+ self,
605
+ buttons: list[Button],
606
+ **kwargs
607
+ ):
608
+ super().__init__(
609
+ buttons=buttons,
610
+ **kwargs
611
+ )
612
+
201
613
 
202
614
  class Keypad(DataManager):
203
615
  rows: list[KeypadRow]
204
616
  resize_keyboard: bool = True
205
617
  on_time_keyboard: bool = False
206
618
 
619
+ def __init__(
620
+ self,
621
+ rows: list[KeypadRow],
622
+ resize_keyboard: bool = True,
623
+ on_time_keyboard: bool = False,
624
+ **kwargs
625
+ ):
626
+ super().__init__(
627
+ rows=rows,
628
+ resize_keyboard=resize_keyboard,
629
+ on_time_keyboard=on_time_keyboard,
630
+ **kwargs
631
+ )
632
+
207
633
 
208
634
  class MessageKeypadUpdate(DataManager):
209
635
  message_id: Optional[str] = None
210
636
  inline_keypad: Optional[Keypad] = None
211
637
 
638
+ def __init__(
639
+ self,
640
+ message_id: Optional[str] = None,
641
+ inline_keypad: Optional[Keypad] = None,
642
+ **kwargs
643
+ ):
644
+ super().__init__(
645
+ message_id=message_id,
646
+ inline_keypad=inline_keypad,
647
+ **kwargs
648
+ )
649
+
212
650
 
213
651
  class Message(DataManager):
214
652
  message_id: Optional[str] = None
@@ -228,6 +666,46 @@ class Message(DataManager):
228
666
  poll: Optional[Poll] = None
229
667
  live_location: Optional[LiveLocation] = None
230
668
 
669
+ def __init__(
670
+ self,
671
+ message_id: Optional[str] = None,
672
+ text: Optional[str] = None,
673
+ time: Optional[str] = None,
674
+ is_edited: Optional[bool] = None,
675
+ sender_type: Optional[enums.MessageSender] = None,
676
+ sender_id: Optional[str] = None,
677
+ aux_data: Optional[AuxData] = None,
678
+ file: Optional[File] = None,
679
+ reply_to_message_id: Optional[str] = None,
680
+ forwarded_from: Optional[ForwardedFrom] = None,
681
+ forwarded_no_link: Optional[str] = None,
682
+ location: Optional[Location] = None,
683
+ sticker: Optional[Sticker] = None,
684
+ contact_message: Optional[ContactMessage] = None,
685
+ poll: Optional[Poll] = None,
686
+ live_location: Optional[LiveLocation] = None,
687
+ **kwargs
688
+ ):
689
+ super().__init__(
690
+ message_id=message_id,
691
+ text=text,
692
+ time=time,
693
+ is_edited=is_edited,
694
+ sender_type=sender_type,
695
+ sender_id=sender_id,
696
+ aux_data=aux_data,
697
+ file=file,
698
+ reply_to_message_id=reply_to_message_id,
699
+ forwarded_from=forwarded_from,
700
+ forwarded_no_link=forwarded_no_link,
701
+ location=location,
702
+ sticker=sticker,
703
+ contact_message=contact_message,
704
+ poll=poll,
705
+ live_location=live_location,
706
+ **kwargs
707
+ )
708
+
231
709
 
232
710
  class MessageId(DataManager):
233
711
  message_id: Optional[str] = None
@@ -235,6 +713,22 @@ class MessageId(DataManager):
235
713
  chat_id: Optional[str] = None
236
714
  client: Optional[Any] = None
237
715
 
716
+ def __init__(
717
+ self,
718
+ message_id: Optional[str] = None,
719
+ file_id: Optional[str] = None,
720
+ chat_id: Optional[str] = None,
721
+ client: Optional[Any] = None,
722
+ **kwargs
723
+ ):
724
+ super().__init__(
725
+ message_id=message_id,
726
+ file_id=file_id,
727
+ chat_id=chat_id,
728
+ client=client,
729
+ **kwargs
730
+ )
731
+
238
732
  async def delete(self):
239
733
  return await self.client.delete_message(self.chat_id, self.message_id)
240
734
 
@@ -257,6 +751,26 @@ class Update(DataManager):
257
751
  updated_message: Optional[Message] = None
258
752
  updated_payment: Optional[PaymentStatus] = None
259
753
 
754
+ def __init__(
755
+ self,
756
+ type: Optional[enums.UpdateType] = None,
757
+ chat_id: Optional[str] = None,
758
+ removed_message_id: Optional[str] = None,
759
+ new_message: Optional[Message] = None,
760
+ updated_message: Optional[Message] = None,
761
+ updated_payment: Optional[PaymentStatus] = None,
762
+ **kwargs
763
+ ):
764
+ super().__init__(
765
+ type=type,
766
+ chat_id=chat_id,
767
+ removed_message_id=removed_message_id,
768
+ new_message=new_message,
769
+ updated_message=updated_message,
770
+ updated_payment=updated_payment,
771
+ **kwargs
772
+ )
773
+
260
774
  async def download(self, file_name: str):
261
775
  return await self.client.download_file(self.new_message.file.file_id, file_name)
262
776
 
@@ -363,9 +877,9 @@ class Update(DataManager):
363
877
 
364
878
  async def reply_file(
365
879
  self,
366
- file: str,
367
- file_name: str,
368
- caption: str = None,
880
+ file: Union[str, bytes],
881
+ caption: Optional[str] = None,
882
+ file_name: Optional[str] = None,
369
883
  type: enums.FileType = enums.FileType.File,
370
884
  chat_keypad: Keypad = None,
371
885
  inline_keypad: Keypad = None,
@@ -375,8 +889,8 @@ class Update(DataManager):
375
889
  return await self.client.send_file(
376
890
  self.chat_id,
377
891
  file,
378
- file_name,
379
892
  caption,
893
+ file_name,
380
894
  type,
381
895
  chat_keypad,
382
896
  inline_keypad,
@@ -385,28 +899,23 @@ class Update(DataManager):
385
899
  self.new_message.message_id,
386
900
  )
387
901
 
388
- async def reply_document(self, document: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
389
- return await self.reply_file(document, name, caption, "File", **kwargs)
902
+ async def reply_document(self, document: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
903
+ return await self.reply_file(document, caption, file_name, "File", **kwargs)
390
904
 
391
- async def reply_photo(self, photo: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
392
- return await self.reply_file(photo, name, caption, "Image", **kwargs)
905
+ async def reply_photo(self, photo: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
906
+ return await self.reply_file(photo, caption, file_name, "Image", **kwargs)
393
907
 
394
- async def reply_video(self, video: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
395
- return await self.reply_file(video, name, caption, "Video", **kwargs)
908
+ async def reply_video(self, video: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
909
+ return await self.reply_file(video, caption, file_name, "Video", **kwargs)
396
910
 
397
- async def reply_gif(self, gif: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
398
- return await self.reply_file(gif, name, caption, "Gif", **kwargs)
911
+ async def reply_gif(self, gif: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
912
+ return await self.reply_file(gif, caption, file_name, "Gif", **kwargs)
399
913
 
400
- async def reply_music(self, music: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
401
- return await self.reply_file(music, name, caption, "Music", **kwargs)
914
+ async def reply_music(self, music: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
915
+ return await self.reply_file(music, caption, file_name, "Music", **kwargs)
402
916
 
403
- async def reply_voice(self, voice: str, name: str, caption: Optional[str] = None, **kwargs) -> "MessageId":
404
- return await self.reply_file(voice, name, caption, "Voice", **kwargs)
405
-
406
-
407
- class Updates(DataManager):
408
- updates: Optional[list[Update]] = None
409
- next_offset_id: Optional[str] = None
917
+ async def reply_voice(self, voice: Union[str, bytes], caption: Optional[str] = None, file_name: Optional[str] = None, **kwargs) -> "MessageId":
918
+ return await self.reply_file(voice, caption, file_name, "Voice", **kwargs)
410
919
 
411
920
 
412
921
  class InlineMessage(DataManager):
@@ -417,4 +926,43 @@ class InlineMessage(DataManager):
417
926
  chat_id: Optional[str] = None
418
927
  file: Optional[File] = None
419
928
  location: Optional[Location] = None
420
- aux_data: Optional[AuxData] = None
929
+ aux_data: Optional[AuxData] = None
930
+
931
+ def __init__(
932
+ self,
933
+ sender_id: Optional[str] = None,
934
+ text: Optional[str] = None,
935
+ message_id: Optional[str] = None,
936
+ chat_id: Optional[str] = None,
937
+ file: Optional[File] = None,
938
+ location: Optional[Location] = None,
939
+ aux_data: Optional[AuxData] = None,
940
+ **kwargs
941
+ ):
942
+ super().__init__(
943
+ sender_id=sender_id,
944
+ text=text,
945
+ message_id=message_id,
946
+ chat_id=chat_id,
947
+ file=file,
948
+ location=location,
949
+ aux_data=aux_data,
950
+ **kwargs
951
+ )
952
+
953
+
954
+ class Updates(DataManager):
955
+ updates: Optional[list[Update]] = None
956
+ next_offset_id: Optional[str] = None
957
+
958
+ def __init__(
959
+ self,
960
+ updates: Optional[list[Update]] = None,
961
+ next_offset_id: Optional[str] = None,
962
+ **kwargs
963
+ ):
964
+ super().__init__(
965
+ updates=updates,
966
+ next_offset_id=next_offset_id,
967
+ **kwargs
968
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RubigramClient
3
- Version: 1.6.6
3
+ Version: 1.6.7
4
4
  Summary: A simple and flexible Python library for building advanced Rubika bots with powerful message handling, inline buttons, and custom filters.
5
5
  Author-email: Javad RZ <MrJavad.Email@gmail.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -31,7 +31,8 @@ bot = Client(token="YOUR_TOKEN_BOT")
31
31
 
32
32
  @bot.on_message(filters.private)
33
33
  async def welcome_message(client, message: Update):
34
- await message.reply("Hi, WELCOME TO RUBIGRAM")
34
+ send = await message.reply("Hi, WELCOME TO RUBIGRAM")
35
+ await send.edit_text("message was edited")
35
36
 
36
37
  bot.run()
37
38
  ```
@@ -84,3 +85,22 @@ async def main():
84
85
 
85
86
  asyncio.run(main())
86
87
  ```
88
+
89
+ ## Implementation of multiple programs
90
+ ```python
91
+ from rubigram import Client
92
+ import asyncio
93
+
94
+ tokens = [
95
+ "TOKEN_1",
96
+ "TOKEN_2"
97
+ ]
98
+
99
+ async def main():
100
+ for token in tokens:
101
+ async with Client(token) as bot:
102
+ get_me = await bot.get_me()
103
+ print(get_me.asjson())
104
+
105
+ asyncio.run(main())
106
+ ```
@@ -0,0 +1,13 @@
1
+ rubigram/__init__.py,sha256=h2O7aVl3woDBTHX0MdZLbhgvVRTyXA0NTzOz7F8Y7Xg,124
2
+ rubigram/client.py,sha256=Pg50Za2idur97ZgphmXgQvu0n0N63oPE04sqhujgNk0,5940
3
+ rubigram/enums.py,sha256=UZKH1wROBVMuHVEjrnQSwpi-y2MxMI7zl2uThdPTWoc,2722
4
+ rubigram/filters.py,sha256=40znxAC7xAFYCeERlPYLSVtr0lxUcnQY2HRwt1zSfdk,6838
5
+ rubigram/method.py,sha256=T_JpN6pF-xjRaw__If48H-63tzjFM8VZaUCTqd4vL2I,11501
6
+ rubigram/network.py,sha256=v_JQpVMrHUwDk5oBXgjIBmLGYtyDxUPu7Qvqvk2XUy0,2862
7
+ rubigram/state.py,sha256=_g13o87MHfuudbgvbfu9vAOrSzw4GhdEYkD6dSn7t2s,997
8
+ rubigram/types.py,sha256=MrggHVI62icQpVhVASXI7UV5pav-HuHB6wwVzyg9P90,29326
9
+ rubigramclient-1.6.7.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ rubigramclient-1.6.7.dist-info/METADATA,sha256=RMfK7tSH7TDK1c2h5a_CocA5PVh5ogX8MPxZKtomGI4,2655
11
+ rubigramclient-1.6.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ rubigramclient-1.6.7.dist-info/top_level.txt,sha256=Mhg5HfkL6rLec5sI4ClGmwoqYUANAZUz8sVa1sT_cas,9
13
+ rubigramclient-1.6.7.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- rubigram/__init__.py,sha256=h2O7aVl3woDBTHX0MdZLbhgvVRTyXA0NTzOz7F8Y7Xg,124
2
- rubigram/client.py,sha256=CeSrSsPTg7cF0JSUXgzUVLU4ULD4dhvTZ28zY8zgDDE,5011
3
- rubigram/enums.py,sha256=UZKH1wROBVMuHVEjrnQSwpi-y2MxMI7zl2uThdPTWoc,2722
4
- rubigram/filters.py,sha256=40znxAC7xAFYCeERlPYLSVtr0lxUcnQY2HRwt1zSfdk,6838
5
- rubigram/method.py,sha256=Ltlfh1Jy26CKfCz5fez2jifWWCfB8mAWBQKmAu20I0E,11076
6
- rubigram/network.py,sha256=84-2Grde0GUDOpia6O-7oJNlupBw30ga5VE4sve31dY,2361
7
- rubigram/state.py,sha256=_g13o87MHfuudbgvbfu9vAOrSzw4GhdEYkD6dSn7t2s,997
8
- rubigram/types.py,sha256=9eA-mbhW8ILK0MJ4oJMhK00XRHvUe4EumgECgHNPvVM,13395
9
- rubigramclient-1.6.6.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- rubigramclient-1.6.6.dist-info/METADATA,sha256=gJan_rPbbbecSrLfkpibqZzyIUfOxcmnqLEH_1Qdk5M,2260
11
- rubigramclient-1.6.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- rubigramclient-1.6.6.dist-info/top_level.txt,sha256=Mhg5HfkL6rLec5sI4ClGmwoqYUANAZUz8sVa1sT_cas,9
13
- rubigramclient-1.6.6.dist-info/RECORD,,