Rubka 6.8.5__py3-none-any.whl → 7.1.1__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
@@ -1016,7 +1016,8 @@ class Robot:
1016
1016
  inline_keypad: Optional[Dict[str, Any]] = None,
1017
1017
  disable_notification: bool = False,
1018
1018
  reply_to_message_id: Optional[str] = None,
1019
- chat_keypad_type: Optional[Literal["New", "Removed"]] = None
1019
+ chat_keypad_type: Optional[Literal["New", "Removed"]] = None,
1020
+ delete_after = None
1020
1021
  ) -> Dict[str, Any]:
1021
1022
  """
1022
1023
  Send a text message to a chat.
rubka/asynco.py CHANGED
@@ -1,4 +1,4 @@
1
- import asyncio,aiohttp,aiofiles,time,datetime,json,tempfile,os,sys,subprocess,mimetypes,time, hashlib
1
+ import asyncio,aiohttp,aiofiles,time,datetime,json,tempfile,os,sys,subprocess,mimetypes,time, hashlib,sqlite3
2
2
  from typing import List, Optional, Dict, Any, Literal, Callable, Union,Set
3
3
  from collections import OrderedDict
4
4
  from .exceptions import APIRequestError,raise_for_status,InvalidAccessError,InvalidInputError,TooRequestError,InvalidTokenError
@@ -19,7 +19,6 @@ from tqdm import tqdm
19
19
  API_URL = "https://botapi.rubika.ir/v3"
20
20
 
21
21
  def install_package(package_name: str) -> bool:
22
- """Installs a package using pip."""
23
22
  try:
24
23
  subprocess.check_call([sys.executable, "-m", "pip", "install", package_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
25
24
  return True
@@ -27,7 +26,6 @@ def install_package(package_name: str) -> bool:
27
26
  return False
28
27
 
29
28
  def get_importlib_metadata():
30
- """Dynamically imports and returns metadata functions from importlib."""
31
29
  try:
32
30
  from importlib.metadata import version, PackageNotFoundError
33
31
  return version, PackageNotFoundError
@@ -43,7 +41,6 @@ def get_importlib_metadata():
43
41
  version, PackageNotFoundError = get_importlib_metadata()
44
42
 
45
43
  def get_installed_version(package_name: str) -> Optional[str]:
46
- """Gets the installed version of a package."""
47
44
  if version is None:
48
45
  return "unknown"
49
46
  try:
@@ -52,7 +49,6 @@ def get_installed_version(package_name: str) -> Optional[str]:
52
49
  return None
53
50
 
54
51
  async def get_latest_version(package_name: str) -> Optional[str]:
55
- """Fetches the latest version of a package from PyPI asynchronously."""
56
52
  url = f"https://pypi.org/pypi/{package_name}/json"
57
53
  try:
58
54
  async with aiohttp.ClientSession() as session:
@@ -64,7 +60,6 @@ async def get_latest_version(package_name: str) -> Optional[str]:
64
60
  return None
65
61
 
66
62
  async def check_rubka_version():
67
- """Checks for outdated 'rubka' package and warns the user."""
68
63
  package_name = "rubka"
69
64
  installed_version = get_installed_version(package_name)
70
65
  if installed_version is None:
@@ -87,7 +82,6 @@ async def check_rubka_version():
87
82
 
88
83
 
89
84
  def show_last_six_words(text: str) -> str:
90
- """Returns the last 6 characters of a stripped string."""
91
85
  text = text.strip()
92
86
  return text[-6:]
93
87
  class AttrDict(dict):
@@ -170,12 +164,16 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
170
164
  self._max_cache_size = max_cache_size
171
165
  self._callback_handlers: List[dict] = []
172
166
  self._edited_message_handlers = []
167
+ self._message_saver_enabled = False
168
+ self._max_messages = None
169
+ self._db_path = os.path.join(os.getcwd(), "RubkaSaveMessage.db")
170
+ self._ensure_db()
173
171
  self._message_handlers: List[dict] = []
174
172
 
175
173
  logger.info(f"Initialized RubikaBot with token: {token[:8]}***")
176
174
  async def _get_session(self) -> aiohttp.ClientSession:
177
175
  if self._aiohttp_session is None or self._aiohttp_session.closed:
178
- connector = aiohttp.TCPConnector(limit=100, ssl=False) # limit اتصالات همزمان
176
+ connector = aiohttp.TCPConnector(limit=100, ssl=False)
179
177
  timeout = aiohttp.ClientTimeout(total=self.timeout)
180
178
  self._aiohttp_session = aiohttp.ClientSession(connector=connector, timeout=timeout)
181
179
  return self._aiohttp_session
@@ -251,15 +249,157 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
251
249
  raw = f"{message_id}:{update_type}:{msg_data.get('text','')}:{msg_data.get('author_guid','')}"
252
250
  return hashlib.sha1(raw.encode()).hexdigest()
253
251
  async def get_me(self) -> Dict[str, Any]:
254
- """Get info about the bot itself."""
255
252
  return await self._post("getMe", {})
256
253
  async def geteToken(self):
257
- """Check if the bot token is valid."""
258
254
  if (await self.get_me())['status'] != "OK":
259
255
  raise InvalidTokenError("The provided bot token is invalid or expired.")
260
256
  from typing import Callable, Any, Optional, List
261
257
 
262
258
 
259
+ #save message database __________________________
260
+
261
+ def _ensure_db(self):
262
+ conn = sqlite3.connect(self._db_path)
263
+ cur = conn.cursor()
264
+ cur.execute("""
265
+ CREATE TABLE IF NOT EXISTS messages (
266
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
267
+ chat_id TEXT NOT NULL,
268
+ message_id TEXT NOT NULL,
269
+ sender_id TEXT,
270
+ text TEXT,
271
+ raw_data TEXT,
272
+ time TEXT,
273
+ saved_at INTEGER
274
+ );
275
+ """)
276
+ cur.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx_chat_message ON messages(chat_id, message_id);")
277
+ conn.commit()
278
+ conn.close()
279
+
280
+ def _insert_message(self, record: dict):
281
+ conn = sqlite3.connect(self._db_path)
282
+ cur = conn.cursor()
283
+ cur.execute("""
284
+ INSERT OR IGNORE INTO messages
285
+ (chat_id, message_id, sender_id, text, raw_data, time, saved_at)
286
+ VALUES (?, ?, ?, ?, ?, ?, ?)
287
+ """, (
288
+ record.get("chat_id"),
289
+ record.get("message_id"),
290
+ record.get("sender_id"),
291
+ record.get("text"),
292
+ json.dumps(record.get("raw_data") or {}, ensure_ascii=False),
293
+ record.get("time"),
294
+ int(time.time())
295
+ ))
296
+ conn.commit()
297
+ if getattr(self, "_max_messages", None) is not None:
298
+ cur.execute("SELECT COUNT(*) FROM messages")
299
+ total = cur.fetchone()[0]
300
+ if total > self._max_messages:
301
+ remove_count = total - self._max_messages
302
+ cur.execute(
303
+ "DELETE FROM messages WHERE id IN (SELECT id FROM messages ORDER BY saved_at ASC LIMIT ?)",
304
+ (remove_count,)
305
+ )
306
+ conn.commit()
307
+
308
+ conn.close()
309
+
310
+ def _fetch_message(self, chat_id: str, message_id: str):
311
+ conn = sqlite3.connect(self._db_path)
312
+ cur = conn.cursor()
313
+ cur.execute(
314
+ "SELECT chat_id, message_id, sender_id, text, raw_data, time, saved_at FROM messages WHERE chat_id=? AND message_id=?",
315
+ (chat_id, message_id)
316
+ )
317
+ row = cur.fetchone()
318
+ conn.close()
319
+ if not row:
320
+ return None
321
+ chat_id, message_id, sender_id, text, raw_data_json, time_val, saved_at = row
322
+ try:
323
+ raw = json.loads(raw_data_json)
324
+ except:
325
+ raw = {}
326
+ return {
327
+ "chat_id": chat_id,
328
+ "message_id": message_id,
329
+ "sender_id": sender_id,
330
+ "text": text,
331
+ "raw_data": raw,
332
+ "time": time_val,
333
+ "saved_at": saved_at
334
+ }
335
+ async def save_message(self, message: Message):
336
+ try:
337
+ record = {
338
+ "chat_id": getattr(message, "chat_id", None),
339
+ "message_id": getattr(message, "message_id", None),
340
+ "sender_id": getattr(message, "author_guid", None),
341
+ "text": getattr(message, "text", None),
342
+ "raw_data": getattr(message, "raw_data", {}),
343
+ "time": getattr(message, "time", None),
344
+ }
345
+ await asyncio.to_thread(self._insert_message, record)
346
+ except Exception as e:
347
+ print(f"[DB] Error saving message: {e}")
348
+
349
+ async def get_message(self, chat_id: str, message_id: str):
350
+ return await asyncio.to_thread(self._fetch_message, chat_id, message_id)
351
+
352
+ def start_save_message(self, max_messages: int = 1000):
353
+ if self._message_saver_enabled:
354
+ return
355
+ self._message_saver_enabled = True
356
+ self._max_messages = max_messages
357
+ decorators = [
358
+ "on_message", "on_edited_message", "on_message_file", "on_message_forwarded",
359
+ "on_message_reply", "on_message_text", "on_update", "on_callback",
360
+ "on_callback_query", "callback_query_handler", "callback_query",
361
+ "on_inline_query", "on_inline_query_prefix", "on_message_private", "on_message_group"
362
+ ]
363
+
364
+ for decorator_name in decorators:
365
+ if hasattr(self, decorator_name):
366
+ original_decorator = getattr(self, decorator_name)
367
+
368
+ def make_wrapper(orig_decorator):
369
+ def wrapper(*args, **kwargs):
370
+ decorator = orig_decorator(*args, **kwargs)
371
+ def inner_wrapper(func):
372
+ async def inner(bot, message, *a, **kw):
373
+ try:
374
+ await bot.save_message(message)
375
+ if getattr(self, "_max_messages", None) is not None:
376
+ await asyncio.to_thread(self._prune_old_messages)
377
+ except Exception as e:
378
+ print(f"[DB] Save error: {e}")
379
+ return await func(bot, message, *a, **kw)
380
+ return decorator(inner)
381
+ return inner_wrapper
382
+ return wrapper
383
+
384
+ setattr(self, decorator_name, make_wrapper(original_decorator))
385
+ def _prune_old_messages(self):
386
+ if not hasattr(self, "_max_messages") or self._max_messages is None:
387
+ return
388
+ conn = sqlite3.connect(self._db_path)
389
+ cur = conn.cursor()
390
+ cur.execute("SELECT COUNT(*) FROM messages")
391
+ total = cur.fetchone()[0]
392
+ if total > self._max_messages:
393
+ remove_count = total - self._max_messages
394
+ cur.execute(
395
+ "DELETE FROM messages WHERE id IN (SELECT id FROM messages ORDER BY saved_at ASC LIMIT ?)",
396
+ (remove_count,)
397
+ )
398
+ conn.commit()
399
+ conn.close()
400
+
401
+ #save message database __________________________ end
402
+
263
403
  #decorator#
264
404
 
265
405
  def on_message_private(
@@ -852,7 +992,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
852
992
  asyncio.create_task(handler_info["func"](self, context))
853
993
  continue
854
994
  if handler_info["commands"] or handler_info["filters"]:
855
- asyncio.create_task(handler_info["func"](self, context))#jaq
995
+ asyncio.create_task(handler_info["func"](self, context))#kir baba kir
856
996
  continue
857
997
  elif update.get("type") == "UpdatedMessage":
858
998
  msg = update.get("updated_message", {})
@@ -912,7 +1052,7 @@ max_cache_size and max_msg_age help manage duplicate message processing efficien
912
1052
  async def run(
913
1053
  self,
914
1054
  debug: bool = False,
915
- sleep_time: float = 0.2,
1055
+ sleep_time: float = 0.1,
916
1056
  webhook_timeout: int = 20,
917
1057
  update_limit: int = 100,
918
1058
  retry_delay: float = 5.0,
rubka/context.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Any, Dict, List,Optional
2
2
  from typing import Union
3
3
  from pathlib import Path
4
- import re
4
+ import re,inspect
5
5
  import asyncio
6
6
  class File:
7
7
  def __init__(self, data: dict):
@@ -265,24 +265,68 @@ class Message:
265
265
  self.bot.sessions[self.chat_id] = {}
266
266
  return self.bot.sessions[self.chat_id]
267
267
 
268
- async def reply(self, text: str, delete_after: int = None, **kwargs):
269
- msg = await self.bot.send_message(
270
- self.chat_id,
271
- text,
272
- reply_to_message_id=self.message_id,
273
- delete_after=delete_after,
274
- **kwargs
275
- )
276
- class pick:
277
- def __init__(self, bot, chat_id, message_id):
278
- self.bot = bot
279
- self.chat_id = chat_id
280
- self.message_id = message_id
281
- async def edit(self, new_text):
282
- await self.bot.edit_message_text(self.chat_id, self.message_id, new_text)
283
- async def delete(self):
284
- await self.bot.delete_message(self.chat_id, self.message_id)
285
- return pick(self.bot, msg.chat_id, msg.message_id)
268
+ def reply(self, text: str, delete_after: int = None, **kwargs):
269
+ async def _reply_async():
270
+ send_func = self.bot.send_message
271
+ if inspect.iscoroutinefunction(send_func):
272
+ msg = await send_func(
273
+ self.chat_id,
274
+ text,
275
+ reply_to_message_id=self.message_id,
276
+ delete_after=delete_after,
277
+ **kwargs
278
+ )
279
+ else:
280
+ msg = send_func(
281
+ self.chat_id,
282
+ text,
283
+ reply_to_message_id=self.message_id,
284
+ delete_after=delete_after,
285
+ **kwargs
286
+ )
287
+ class Pick:
288
+ def __init__(self, bot, chat_id, message_id):
289
+ self.bot = bot
290
+ self.chat_id = chat_id
291
+ self.message_id = message_id
292
+
293
+ def edit(self, new_text):
294
+ async def _edit():
295
+ func = self.bot.edit_message_text
296
+ if inspect.iscoroutinefunction(func):
297
+ await func(self.chat_id, self.message_id, new_text)
298
+ else:
299
+ func(self.chat_id, self.message_id, new_text)
300
+
301
+ try:
302
+ loop = asyncio.get_running_loop()
303
+ if loop.is_running():
304
+ return asyncio.create_task(_edit())
305
+ except RuntimeError:
306
+ return asyncio.run(_edit())
307
+
308
+ def delete(self):
309
+ async def _delete():
310
+ func = self.bot.delete_message
311
+ if inspect.iscoroutinefunction(func):
312
+ await func(self.chat_id, self.message_id)
313
+ else:
314
+ func(self.chat_id, self.message_id)
315
+ try:
316
+ loop = asyncio.get_running_loop()
317
+ if loop.is_running():
318
+ return asyncio.create_task(_delete())
319
+ except RuntimeError:
320
+ return asyncio.run(_delete())
321
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
322
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
323
+ return Pick(self.bot, chat_id, message_id)
324
+ try:
325
+ loop = asyncio.get_running_loop()
326
+ if loop.is_running():
327
+ return asyncio.create_task(_reply_async())
328
+ except RuntimeError:
329
+ return asyncio.run(_reply_async())
286
330
  def answer(self, text: str, **kwargs):
287
331
  return self.bot.send_message(
288
332
  self.chat_id,
rubka/update.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Any, Dict, List,Optional
2
2
  from typing import Union
3
3
  from pathlib import Path
4
- import re
4
+ import re,inspect
5
5
  import asyncio
6
6
  class File:
7
7
  def __init__(self, data: dict):
@@ -259,20 +259,74 @@ class Message:
259
259
  self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
260
260
  self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
261
261
  self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
262
- self.info = {attr: value for attr, value in vars(self).items()}
263
262
  @property
264
263
  def session(self):
265
264
  if self.chat_id not in self.bot.sessions:
266
265
  self.bot.sessions[self.chat_id] = {}
267
266
  return self.bot.sessions[self.chat_id]
268
- def reply(self, text: str,delete_after :int = None, **kwargs):
269
- return self.bot.send_message(
270
- self.chat_id,
271
- text,
272
- reply_to_message_id=self.message_id,
273
- delete_after=delete_after,
274
- **kwargs
275
- )
267
+
268
+ def reply(self, text: str, delete_after: int = None, **kwargs):
269
+ async def _reply_async():
270
+ send_func = self.bot.send_message
271
+ if inspect.iscoroutinefunction(send_func):
272
+ msg = await send_func(
273
+ self.chat_id,
274
+ text,
275
+ reply_to_message_id=self.message_id,
276
+ delete_after=delete_after,
277
+ **kwargs
278
+ )
279
+ else:
280
+ msg = send_func(
281
+ self.chat_id,
282
+ text,
283
+ reply_to_message_id=self.message_id,
284
+ delete_after=delete_after,
285
+ **kwargs
286
+ )
287
+ class Pick:
288
+ def __init__(self, bot, chat_id, message_id):
289
+ self.bot = bot
290
+ self.chat_id = chat_id
291
+ self.message_id = message_id
292
+
293
+ def edit(self, new_text):
294
+ async def _edit():
295
+ func = self.bot.edit_message_text
296
+ if inspect.iscoroutinefunction(func):
297
+ await func(self.chat_id, self.message_id, new_text)
298
+ else:
299
+ func(self.chat_id, self.message_id, new_text)
300
+
301
+ try:
302
+ loop = asyncio.get_running_loop()
303
+ if loop.is_running():
304
+ return asyncio.create_task(_edit())
305
+ except RuntimeError:
306
+ return asyncio.run(_edit())
307
+
308
+ def delete(self):
309
+ async def _delete():
310
+ func = self.bot.delete_message
311
+ if inspect.iscoroutinefunction(func):
312
+ await func(self.chat_id, self.message_id)
313
+ else:
314
+ func(self.chat_id, self.message_id)
315
+ try:
316
+ loop = asyncio.get_running_loop()
317
+ if loop.is_running():
318
+ return asyncio.create_task(_delete())
319
+ except RuntimeError:
320
+ return asyncio.run(_delete())
321
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
322
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
323
+ return Pick(self.bot, chat_id, message_id)
324
+ try:
325
+ loop = asyncio.get_running_loop()
326
+ if loop.is_running():
327
+ return asyncio.create_task(_reply_async())
328
+ except RuntimeError:
329
+ return asyncio.run(_reply_async())
276
330
  def answer(self, text: str, **kwargs):
277
331
  return self.bot.send_message(
278
332
  self.chat_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 6.8.5
3
+ Version: 7.1.1
4
4
  Summary: rubika 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/v6.6.4.zip
@@ -31,6 +31,7 @@ Requires-Dist: Pillow
31
31
  Requires-Dist: websocket-client
32
32
  Requires-Dist: pycryptodome
33
33
  Requires-Dist: aiohttp
34
+ Requires-Dist: httpx
34
35
  Requires-Dist: tqdm
35
36
  Requires-Dist: mutagen
36
37
  Requires-Dist: filetype
@@ -1,9 +1,9 @@
1
1
  rubka/__init__.py,sha256=P6IBiORfp-GqKHe5LZ-5lldWyG7tnrUYUcAQDUgwXmY,1973
2
- rubka/api.py,sha256=1S8JIcYN_Zxb7JT73eQl9me-qDDDTDzcSk6_qawAfkA,68861
3
- rubka/asynco.py,sha256=zna9bPhuDo9Kfut6gxT7nbE2kXvjCMp0Vwm8naOTH30,102328
2
+ rubka/api.py,sha256=fo4X9MH_HqQmLkRNhjJcJJZOHp5lkFZqitCXs2qL_kc,68891
3
+ rubka/asynco.py,sha256=CD_4UBhRSE5RxgVSJKb7_nBcRE7YowKeEHeYeyfYmY4,107945
4
4
  rubka/button.py,sha256=vU9OvWXCD4MRrTJ8Xmivd4L471-06zrD2qpZBTw5vjY,13305
5
5
  rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
6
- rubka/context.py,sha256=qZUhYbc__jBMvh3HEc1tsN-4N-naOeRJyKMmHYw7940,32280
6
+ rubka/context.py,sha256=-oC9h7U_H3CrtqUCDCnFXAvC7zdSmwxlc0CNwL1XLxM,34314
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
@@ -14,7 +14,7 @@ rubka/keypad.py,sha256=yGsNt8W5HtUFBzVF1m_p7GySlu1hwIcSvXZ4BTdrlvg,9558
14
14
  rubka/logger.py,sha256=J2I6NiK1z32lrAzC4H1Et6WPMBXxXGCVUsW4jgcAofs,289
15
15
  rubka/rubino.py,sha256=GuXnEUTTSZUw68FMTQBYsB2zG_3rzdDa-krsrl4ib8w,58755
16
16
  rubka/tv.py,sha256=o7CW-6EKLhmM--rzcHcKPcXfzOixcL_B4j037R3mHts,5399
17
- rubka/update.py,sha256=rCqqxInnDJYnwXy659vSzh7rk3snBy0cTqefaDtn0a4,31826
17
+ rubka/update.py,sha256=-oC9h7U_H3CrtqUCDCnFXAvC7zdSmwxlc0CNwL1XLxM,34314
18
18
  rubka/utils.py,sha256=XUQUZxQt9J2f0X5hmAH_MH1kibTAfdT1T4AaBkBhBBs,148
19
19
  rubka/adaptorrubka/__init__.py,sha256=6o2tCXnVeES7nx-LjnzsuMqjKcWIm9qwKficLE54s-U,83
20
20
  rubka/adaptorrubka/enums.py,sha256=cyiakExmZi-QQpYuf_A93HQvfZVmyG_0uVuvTTNT5To,1053
@@ -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-6.8.5.dist-info/METADATA,sha256=GBV_8B-GISwQoZ6Z8TDTsI2OLxv0xoeeuHVQBcXkJCM,34269
41
- rubka-6.8.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
- rubka-6.8.5.dist-info/entry_points.txt,sha256=4aESuUmuUOALMUy7Kucv_Gb5YlqhsJmTmdXLlZU9sJ0,46
43
- rubka-6.8.5.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
44
- rubka-6.8.5.dist-info/RECORD,,
40
+ rubka-7.1.1.dist-info/METADATA,sha256=mAyvw8N3LjT2Hz7bPllCqAwrs_nvhzvKNtaFKXHjKX4,34291
41
+ rubka-7.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
+ rubka-7.1.1.dist-info/entry_points.txt,sha256=4aESuUmuUOALMUy7Kucv_Gb5YlqhsJmTmdXLlZU9sJ0,46
43
+ rubka-7.1.1.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
44
+ rubka-7.1.1.dist-info/RECORD,,
File without changes