spluspy 2.0.5__tar.gz → 2.0.7__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.
- spluspy-2.0.7/.gitignore +50 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/CHANGELOG.md +30 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/Dockerfile +3 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/MANIFEST.in +1 -1
- {spluspy-2.0.5 → spluspy-2.0.7}/PKG-INFO +366 -45
- {spluspy-2.0.5 → spluspy-2.0.7}/README.md +363 -44
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/01_hello_bot.py +1 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/02_echo_bot.py +1 -1
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/04_private_only.py +3 -4
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/05_group_only.py +3 -4
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/06_regex_bot.py +6 -7
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/07_user_filter.py +5 -6
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/09_inline_keyboard.py +8 -9
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/10_reply_keyboard.py +7 -8
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/11_message_actions.py +10 -12
- spluspy-2.0.7/examples/12_media_bot.py +36 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/13_fsm_bot.py +12 -13
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/14_plugin_bot.py +7 -5
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/15_middleware_bot.py +2 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/pyproject.toml +2 -1
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/__init__.py +28 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/__version__.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/account.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/buttons.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/chats.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/messages.py +3 -3
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/updates.py +2 -2
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/uploads.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/users.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/__init__.py +3 -3
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/album.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/callbackquery.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/chataction.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/inlinequery.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/messagedeleted.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/messageedited.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/messageread.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/newmessage.py +2 -2
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/raw.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/userupdate.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sessions/sqlite.py +5 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/conversation.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/message.py +1 -1
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/utils.py +2 -2
- spluspy-2.0.7/spluspy/admin.py +285 -0
- spluspy-2.0.7/spluspy/afk.py +202 -0
- spluspy-2.0.7/spluspy/client/client.py +3344 -0
- spluspy-2.0.7/spluspy/client/conversation.py +294 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/compat.py +3 -3
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/config.py +2 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/base.py +6 -14
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/filters/__init__.py +2 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/filters/filters.py +36 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/fsm/state.py +9 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/middleware/base.py +26 -6
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/middleware/rate_limit.py +6 -1
- spluspy-2.0.7/spluspy/mirror.py +207 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/bot.py +8 -44
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/chat.py +4 -4
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/media.py +11 -11
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/message.py +15 -80
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/objects.py +6 -6
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/user.py +1 -1
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/__init__.py +10 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/client.py +38 -10
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/mtproto.py +41 -0
- spluspy-2.0.7/spluspy/network/protocols.py +104 -0
- spluspy-2.0.7/spluspy/network/spluspy_adapter.py +465 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/transport.py +6 -62
- spluspy-2.0.7/spluspy/py.typed +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/scheduler/__init__.py +2 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/scheduler/scheduler.py +140 -2
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/session/sqlite.py +12 -15
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/session/string.py +22 -3
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/base.py +9 -2
- spluspy-2.0.7/spluspy/storage/entity_cache.py +280 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/sqlite.py +6 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/__init__.py +6 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/batch.py +1 -1
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/cache.py +54 -3
- spluspy-2.0.7/spluspy/utils/chat_lock.py +96 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/file_transfer.py +85 -15
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/logger.py +282 -284
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/rate_limiter.py +4 -4
- spluspy-2.0.7/spluspy/utils/resolver.py +372 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_client.py +33 -21
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_filters.py +3 -3
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_fsm_enhanced.py +12 -12
- spluspy-2.0.7/tests/test_resolver.py +411 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_storage.py +12 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_types.py +6 -6
- spluspy-2.0.5/debug_client.py +0 -829
- spluspy-2.0.5/examples/12_media_bot.py +0 -38
- spluspy-2.0.5/spluspy/.mimocode/.cron-lock +0 -1
- spluspy-2.0.5/spluspy/client/client.py +0 -1844
- spluspy-2.0.5/spluspy/client/conversation.py +0 -80
- spluspy-2.0.5/spluspy/network/spluspy_adapter.py +0 -306
- spluspy-2.0.5/spluspy/network/telethon_adapter.py +0 -153
- spluspy-2.0.5/tempCodeRunnerFile.py +0 -6
- spluspy-2.0.5/test_handlers.py +0 -85
- spluspy-2.0.5/tests/.vscode/PythonImportHelper-v2-Completion.json +0 -843
- spluspy-2.0.5/tests/test_storage_backends.py +0 -52
- {spluspy-2.0.5 → spluspy-2.0.7}/CONTRIBUTING.md +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/LICENSE +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/README.rst +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/03_command_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/08_combined_filters.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/16_scheduler_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/17_conversation.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/18_chat_management.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/19_event_types.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/20_sync_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/21_album_handler.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/22_download_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/23_url_button.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/24_string_session.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/25_error_handling.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/25_working_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/26_message_entities.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/27_search_messages.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/28_poll_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/29_dice_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/30_cache_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/31_reaction_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/32_mark_read_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/33_context_manager.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/34_user_info.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/35_chat_info.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/36_forward_copy.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/37_admin_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/38_media_filters.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/39_status_bot.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/40_delete_detection.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/41_read_detection.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/42_raw_events.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/43_poll_handler.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/44_reaction_handler.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/45_typing_handler.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/46_get_messages.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/47_iter_messages.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/48_get_members.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/49_resolve_username.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/examples/50_invoke.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/_updates/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/_updates/entitycache.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/_updates/messagebox.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/_updates/session.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/auth.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/bots.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/dialogs.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/downloads.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/messageparse.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/soroushclient.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/client/telegrambaseclient.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/aes.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/aesctr.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/authkey.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/cdndecrypter.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/factorization.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/libssl.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/crypto/rsa.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/custom.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/errors/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/errors/common.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/errors/rpcbaseerrors.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/errors/rpcerrorlist.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/events/common.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/extensions/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/extensions/binaryreader.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/extensions/html.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/extensions/markdown.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/extensions/messagepacker.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/functions.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/helpers.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/hints.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/authenticator.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/connection.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/http.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/tcpabridged.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/tcpfull.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/tcpintermediate.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/tcpmtproxy.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/tcpobfuscated.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/connection/websocket.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/mtprotoplainsender.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/mtprotosender.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/mtprotostate.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/network/requeststate.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/password.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/requestiter.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sessions/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sessions/abstract.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sessions/memory.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sessions/string.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/sync.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/alltlobjects.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/core/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/core/gzippacked.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/core/messagecontainer.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/core/rpcresult.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/core/tlmessage.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/adminlogevent.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/button.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/chatgetter.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/dialog.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/draft.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/file.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/forward.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/inlinebuilder.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/inlineresult.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/inlineresults.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/inputsizedfile.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/messagebutton.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/participantpermissions.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/qrlogin.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/sendergetter.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/custom/types.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/account.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/auth.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/bots.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/channels.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/chatlists.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/conference.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/contacts.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/folders.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/help.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/langpack.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/messages.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/payments.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/phone.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/photos.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/premium.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/stats.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/stories.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/thirdParty.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/updates.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/upload.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/functions/users.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/patched/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/tlobject.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/__init__.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/account.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/auth.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/bots.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/channels.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/chatlists.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/conference.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/contacts.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/help.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/messages.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/payments.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/phone.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/photos.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/premium.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/stats.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/stickers.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/storage.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/stories.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/thirdParty.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/update.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/updates.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/upload.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/tl/types/users.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/types.py +0 -0
- {spluspy-2.0.5/spluspy/spluspy2 → spluspy-2.0.7/spluspy/_engine}/version.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/cli.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/client/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/errors/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/errors/exceptions.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/album.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/callback.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/chat_action.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/edited.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/inline.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/message.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/message_deleted.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/message_read.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/events/user_update.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/fsm/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/middleware/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/models/enums.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/connection.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/network/http_client.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/plugins/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/plugins/loader.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/session/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/session/base.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/session/memory.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/memory.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/postgres.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/storage/redis.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/sync/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/sync/client.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/helpers.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/spluspy/utils/version_check.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/__init__.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_fsm.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_middleware.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_rate_limiter.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_scheduler.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_session.py +0 -0
- {spluspy-2.0.5 → spluspy-2.0.7}/tests/test_utils.py +0 -0
spluspy-2.0.7/.gitignore
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.whl
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
venv/
|
|
14
|
+
.venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.vscode/
|
|
19
|
+
.idea/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# Testing
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
|
|
30
|
+
# Logs
|
|
31
|
+
*.log
|
|
32
|
+
logs/
|
|
33
|
+
|
|
34
|
+
# Database files
|
|
35
|
+
*.sqlite
|
|
36
|
+
*.sqlite3
|
|
37
|
+
|
|
38
|
+
# Environment
|
|
39
|
+
.env
|
|
40
|
+
.env.*
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
Thumbs.db
|
|
44
|
+
Desktop.ini
|
|
45
|
+
.DS_Store
|
|
46
|
+
|
|
47
|
+
# Temporary files
|
|
48
|
+
tempCodeRunnerFile.py
|
|
49
|
+
*.tmp
|
|
50
|
+
*.bak
|
|
@@ -5,6 +5,36 @@ All notable changes to SplusPy will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [2.0.7] - 2026-07-11
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Version bump to 2.0.7
|
|
12
|
+
|
|
13
|
+
## [2.0.6] - 2026-07-11
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Fixed missing `Union` import in `batch.py` that caused `NameError` at runtime
|
|
17
|
+
- Fixed missing `copy_messages` method call in sync wrapper that caused `AttributeError`
|
|
18
|
+
- Removed unused `SplusConnectionError` import in `client.py`
|
|
19
|
+
- Fixed deprecated `asyncio.get_event_loop()` replaced with `asyncio.get_running_loop()` in network client
|
|
20
|
+
- Fixed FSM `on_enter`/`on_leave` hooks that were registered but never invoked
|
|
21
|
+
- Fixed `RateLimitMiddleware` that incremented counter but didn't actually rate-limit updates
|
|
22
|
+
|
|
23
|
+
### Removed
|
|
24
|
+
- Removed unused `HttpTransport` class from transport module
|
|
25
|
+
- Removed duplicate `test_storage_backends.py` (merged TTL test into `test_storage.py`)
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Renamed `FloodWait` in `rate_limiter.py` to `FloodWaitState` to avoid confusion with `errors.FloodWait`
|
|
29
|
+
- Moved inline `import inspect` and `import re` to module-level imports in `client.py`
|
|
30
|
+
- Added `FloodWaitState` docstring clarification in rate limiter
|
|
31
|
+
|
|
32
|
+
### Documentation
|
|
33
|
+
- Fixed README.md project structure: `types/` corrected to `models/`
|
|
34
|
+
- Fixed README.md FSM example that accessed data after `reset()`
|
|
35
|
+
- Fixed Dockerfile `COPY bot.py` that failed when file doesn't exist
|
|
36
|
+
- Added docstring for `Regex` filter side effect (`pattern_match`)
|
|
37
|
+
|
|
8
38
|
## [3.0.0] - 2026-07-10
|
|
9
39
|
|
|
10
40
|
### Added
|
|
@@ -14,8 +14,9 @@ COPY spluspy/ spluspy/
|
|
|
14
14
|
# Install the package
|
|
15
15
|
RUN pip install --no-cache-dir ".[all]"
|
|
16
16
|
|
|
17
|
-
# Copy bot script
|
|
18
|
-
|
|
17
|
+
# Copy bot script (pass as build arg)
|
|
18
|
+
ARG BOT_SCRIPT=bot.py
|
|
19
|
+
COPY ${BOT_SCRIPT} ./
|
|
19
20
|
|
|
20
21
|
# Run the bot
|
|
21
22
|
CMD ["python", "bot.py"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spluspy
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7
|
|
4
4
|
Summary: A modern async Python library for interacting with Soroush Plus
|
|
5
5
|
Project-URL: Homepage, https://github.com/Itskillmaster/spluspy
|
|
6
6
|
Project-URL: Documentation, https://github.com/Itskillmaster/spluspy#readme
|
|
@@ -36,6 +36,7 @@ Requires-Dist: pytest-cov>=4.0; extra == 'all'
|
|
|
36
36
|
Requires-Dist: pytest>=7.0; extra == 'all'
|
|
37
37
|
Requires-Dist: redis>=4.0; extra == 'all'
|
|
38
38
|
Requires-Dist: ruff>=0.1.0; extra == 'all'
|
|
39
|
+
Requires-Dist: uvloop>=0.19.0; (sys_platform != 'win32') and extra == 'all'
|
|
39
40
|
Provides-Extra: dev
|
|
40
41
|
Requires-Dist: black>=23.0; extra == 'dev'
|
|
41
42
|
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
@@ -50,6 +51,7 @@ Requires-Dist: redis>=4.0; extra == 'redis'
|
|
|
50
51
|
Provides-Extra: speed
|
|
51
52
|
Requires-Dist: cryptg; extra == 'speed'
|
|
52
53
|
Requires-Dist: orjson>=3.9.0; extra == 'speed'
|
|
54
|
+
Requires-Dist: uvloop>=0.19.0; (sys_platform != 'win32') and extra == 'speed'
|
|
53
55
|
Description-Content-Type: text/markdown
|
|
54
56
|
|
|
55
57
|
<div align="center">
|
|
@@ -101,10 +103,20 @@ Built from the ground up with clean architecture, it's designed to feel like [Te
|
|
|
101
103
|
| **Scheduler** | Built-in task scheduler |
|
|
102
104
|
| **Multiple Storage Backends** | Memory, SQLite, Redis, PostgreSQL |
|
|
103
105
|
| **Rate Limiting** | Token bucket algorithm with flood wait handling |
|
|
106
|
+
| **AFK Auto-Reply** | Smart auto-responder with per-chat rate limiting |
|
|
107
|
+
| **Chat Administration** | Ban, mute, pin, purge — high-level admin API |
|
|
108
|
+
| **Message Mirroring** | Real-time message cloning between chats |
|
|
109
|
+
| **Batch Operations** | Send, delete, forward multiple messages at once |
|
|
110
|
+
| **File Transfer with Progress** | Upload/download with progress tracking |
|
|
104
111
|
| **Professional Logging** | Structured, namespaced loggers |
|
|
105
112
|
| **Type Hints Everywhere** | Full type safety |
|
|
106
113
|
| **Clean Architecture** | SOLID principles, modular design |
|
|
107
114
|
|
|
115
|
+
### Requirements
|
|
116
|
+
|
|
117
|
+
- Python 3.10+
|
|
118
|
+
- No external API keys needed (built-in Soroush Plus credentials)
|
|
119
|
+
|
|
108
120
|
### Installation
|
|
109
121
|
|
|
110
122
|
```bash
|
|
@@ -308,9 +320,9 @@ async def process_form(client, message):
|
|
|
308
320
|
await ctx.set_state(Form.age)
|
|
309
321
|
await message.reply("How old are you?")
|
|
310
322
|
elif state == Form.age:
|
|
311
|
-
await ctx.
|
|
323
|
+
data = await ctx.get_data()
|
|
312
324
|
await ctx.reset()
|
|
313
|
-
await message.reply(f"Registered! Name: {
|
|
325
|
+
await message.reply(f"Registered! Name: {data.get('name')}, Age: {message.text}")
|
|
314
326
|
```
|
|
315
327
|
|
|
316
328
|
#### Advanced FSM: State Routing with Decorators
|
|
@@ -435,6 +447,94 @@ value = cache.get("key")
|
|
|
435
447
|
stats = cache.stats() # {'hits': 42, 'misses': 3}
|
|
436
448
|
```
|
|
437
449
|
|
|
450
|
+
### AFK Auto-Reply
|
|
451
|
+
|
|
452
|
+
```python
|
|
453
|
+
from spluspy import Client, filters
|
|
454
|
+
from spluspy.afk import AfkManager
|
|
455
|
+
|
|
456
|
+
bot = Client("my_account")
|
|
457
|
+
afk = AfkManager(bot, message="I'm currently AFK. Back soon!")
|
|
458
|
+
|
|
459
|
+
@bot.on_message(filters.command("afk"))
|
|
460
|
+
async def set_afk(client, message):
|
|
461
|
+
afk.set_afk(True, reason="Lunch break")
|
|
462
|
+
await message.reply("I'm now AFK!")
|
|
463
|
+
|
|
464
|
+
@bot.on_message(filters.command("back"))
|
|
465
|
+
async def unset_afk(client, message):
|
|
466
|
+
afk.set_afk(False)
|
|
467
|
+
await message.reply(f"Back! Sent {afk.total_replies} auto-replies.")
|
|
468
|
+
|
|
469
|
+
@bot.on_message(filters.private & filters.incoming)
|
|
470
|
+
async def auto_reply(client, message):
|
|
471
|
+
if afk.is_afk:
|
|
472
|
+
await afk.handle(message)
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Chat Administration
|
|
476
|
+
|
|
477
|
+
```python
|
|
478
|
+
from spluspy.admin import ChatAdmin
|
|
479
|
+
|
|
480
|
+
admin = ChatAdmin(bot)
|
|
481
|
+
|
|
482
|
+
await admin.ban_user(chat_id, user_id)
|
|
483
|
+
await admin.unban_user(chat_id, user_id)
|
|
484
|
+
await admin.mute_user(chat_id, user_id)
|
|
485
|
+
await admin.unmute_user(chat_id, user_id)
|
|
486
|
+
await admin.pin_message(chat_id, message)
|
|
487
|
+
await admin.unpin_message(chat_id, message)
|
|
488
|
+
await admin.unpin_all(chat_id)
|
|
489
|
+
await admin.purge_messages(chat_id, limit=100)
|
|
490
|
+
|
|
491
|
+
# Bulk actions
|
|
492
|
+
await admin.bulk_action(chat_id, "ban", [user_id1, user_id2, user_id3])
|
|
493
|
+
|
|
494
|
+
# Admin log
|
|
495
|
+
events = await admin.get_admin_log(chat_id, limit=50)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Message Mirroring
|
|
499
|
+
|
|
500
|
+
```python
|
|
501
|
+
from spluspy.mirror import MessageMirror
|
|
502
|
+
|
|
503
|
+
mirror = MessageMirror(bot)
|
|
504
|
+
|
|
505
|
+
# Add a mirroring route
|
|
506
|
+
mirror.add_route(
|
|
507
|
+
source=-1001234567890,
|
|
508
|
+
targets=[-1009876543210, -1001112223334],
|
|
509
|
+
strip_forward=True,
|
|
510
|
+
strip_sender=False,
|
|
511
|
+
add_prefix="[Mirror]"
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
# Or build incrementally
|
|
515
|
+
mirror.add_source(-1001234567890)
|
|
516
|
+
mirror.add_target(-1009876543210)
|
|
517
|
+
|
|
518
|
+
await mirror.start()
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Scheduler
|
|
522
|
+
|
|
523
|
+
```python
|
|
524
|
+
from spluspy.scheduler.scheduler import MessageScheduler
|
|
525
|
+
|
|
526
|
+
scheduler = MessageScheduler(bot)
|
|
527
|
+
|
|
528
|
+
# Send a message every hour
|
|
529
|
+
scheduler.schedule_interval("hourly_greeting", chat_id, "Hello!", interval=3600)
|
|
530
|
+
|
|
531
|
+
# Send a message after a delay
|
|
532
|
+
scheduler.schedule_once("reminder", chat_id, "Don't forget!", delay=300)
|
|
533
|
+
|
|
534
|
+
# Cancel a scheduled task
|
|
535
|
+
scheduler.cancel("hourly_greeting")
|
|
536
|
+
```
|
|
537
|
+
|
|
438
538
|
### Chat Management
|
|
439
539
|
|
|
440
540
|
```python
|
|
@@ -511,25 +611,46 @@ await message.download(progress=tracker)
|
|
|
511
611
|
# Run a bot
|
|
512
612
|
spluspy run bot.py
|
|
513
613
|
|
|
614
|
+
# Run with custom session name
|
|
615
|
+
spluspy run bot.py --session my_bot
|
|
616
|
+
|
|
514
617
|
# Get session info
|
|
515
|
-
spluspy session-info
|
|
618
|
+
spluspy session-info my_session.session
|
|
516
619
|
|
|
517
620
|
# Show version
|
|
518
621
|
spluspy version
|
|
519
622
|
|
|
520
|
-
# Validate
|
|
521
|
-
spluspy validate
|
|
623
|
+
# Validate a bot script for syntax errors
|
|
624
|
+
spluspy validate bot.py
|
|
522
625
|
```
|
|
523
626
|
|
|
524
627
|
### Docker
|
|
525
628
|
|
|
526
629
|
```dockerfile
|
|
527
630
|
FROM python:3.12-slim
|
|
631
|
+
|
|
528
632
|
WORKDIR /app
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
633
|
+
|
|
634
|
+
# Install system dependencies
|
|
635
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
636
|
+
gcc \
|
|
637
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
638
|
+
|
|
639
|
+
# Install spluspy
|
|
640
|
+
RUN pip install --no-cache-dir spluspy[all]
|
|
641
|
+
|
|
642
|
+
# Copy your bot script
|
|
643
|
+
COPY bot.py .
|
|
644
|
+
|
|
645
|
+
# Run the bot
|
|
646
|
+
CMD ["python", "bot.py"]
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Build and run:
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
docker build -t my-spluspy-bot .
|
|
653
|
+
docker run -v ./sessions:/app/sessions my-spluspy-bot
|
|
533
654
|
```
|
|
534
655
|
|
|
535
656
|
### Project Structure
|
|
@@ -541,8 +662,13 @@ spluspy/
|
|
|
541
662
|
├── cli.py # CLI entry point
|
|
542
663
|
├── config.py # Configuration
|
|
543
664
|
├── compat.py # Compatibility layer
|
|
665
|
+
├── afk.py # AFK auto-responder
|
|
666
|
+
├── admin.py # Chat administration
|
|
667
|
+
├── mirror.py # Message mirroring engine
|
|
544
668
|
├── client/ # Client and conversation API
|
|
545
|
-
├──
|
|
669
|
+
│ ├── client.py # Main Client class
|
|
670
|
+
│ └── conversation.py # Conversation API
|
|
671
|
+
├── models/ # Domain models (Message, User, Chat, Media, etc.)
|
|
546
672
|
├── events/ # Event types and builders
|
|
547
673
|
├── filters/ # Composable message filters
|
|
548
674
|
├── errors/ # Custom exception hierarchy
|
|
@@ -554,7 +680,34 @@ spluspy/
|
|
|
554
680
|
├── fsm/ # Finite state machine
|
|
555
681
|
├── scheduler/ # Task scheduler
|
|
556
682
|
├── utils/ # Logger, cache, helpers
|
|
557
|
-
|
|
683
|
+
├── sync/ # Synchronous client wrapper
|
|
684
|
+
└── _engine/ # Low-level MTProto engine
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Error Hierarchy
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
SplusPyError
|
|
691
|
+
├── SoroushPlusAPIError
|
|
692
|
+
│ ├── RPCError
|
|
693
|
+
│ │ ├── FloodWait
|
|
694
|
+
│ │ ├── Unauthorized
|
|
695
|
+
│ │ ├── BadRequest
|
|
696
|
+
│ │ │ ├── ChatNotFound
|
|
697
|
+
│ │ │ ├── UserNotFound
|
|
698
|
+
│ │ │ └── MessageNotFound
|
|
699
|
+
│ │ └── ...
|
|
700
|
+
│ ├── SessionExpiredError
|
|
701
|
+
│ └── SessionError
|
|
702
|
+
├── AuthError
|
|
703
|
+
├── ValidationError
|
|
704
|
+
├── JoinChatError
|
|
705
|
+
│ ├── InvalidInviteLinkError
|
|
706
|
+
│ ├── InviteLinkExpiredError
|
|
707
|
+
│ ├── ChatFullError
|
|
708
|
+
│ ├── ChatDeactivatedError
|
|
709
|
+
│ └── MembershipRequiredError
|
|
710
|
+
└── FloodWaitError (rate limiter)
|
|
558
711
|
```
|
|
559
712
|
|
|
560
713
|
---
|
|
@@ -579,10 +732,20 @@ spluspy/
|
|
|
579
732
|
| **زمانبند (Scheduler)** | زمانبندی داخلی وظایف |
|
|
580
733
|
| **بکاندهای ذخیرهسازی متعدد** | حافظه، SQLite، Redis، PostgreSQL |
|
|
581
734
|
| **محدودیت نرخ (Rate Limiting)** | الگوریتم سطل توکن با مدیریت انتظار سیلاب |
|
|
735
|
+
| **پاسخ خودکار AFK** | پاسخگوی هوشمند با محدودیت نرخ به ازای هر چت |
|
|
736
|
+
| **مدیریت چت** | مسدود کردن، بیصدا کردن، سنجاق، پاکسازی — API مدیریتی |
|
|
737
|
+
| **آینهسازی پیام** | کلون کردن پیام و رسانه به صورت بلادرنگ بین چتها |
|
|
738
|
+
| **عملیات دستهای** | ارسال، حذف، فوروارد چندین پیام به صورت همزمان |
|
|
739
|
+
| **انتقال فایل با پیشرفت** | آپلود/دانلود با ردیابی پیشرفت |
|
|
582
740
|
| **لاگ حرفهای** | لاگرهای ساختاریافته و فضای نامدار |
|
|
583
741
|
| **نوعنویسی در همه جا** | ایمنی کامل نوع |
|
|
584
742
|
| **معماری تمیز** | اصول SOLID، طراحی ماژولار |
|
|
585
743
|
|
|
744
|
+
### پیشنیازها
|
|
745
|
+
|
|
746
|
+
- پایتون 3.10 به بالا
|
|
747
|
+
- نیازی به کلید API خارجی نیست (کلیدهای سروش پلاس به صورت داخلی)
|
|
748
|
+
|
|
586
749
|
### نصب
|
|
587
750
|
|
|
588
751
|
```bash
|
|
@@ -786,9 +949,9 @@ async def process_form(client, message):
|
|
|
786
949
|
await ctx.set_state(Form.age)
|
|
787
950
|
await message.reply("سن شما چقدر است؟")
|
|
788
951
|
elif state == Form.age:
|
|
789
|
-
await ctx.
|
|
952
|
+
data = await ctx.get_data()
|
|
790
953
|
await ctx.reset()
|
|
791
|
-
await message.reply(f"ثبت شد! نام: {
|
|
954
|
+
await message.reply(f"ثبت شد! نام: {data.get('name')}, سن: {message.text}")
|
|
792
955
|
```
|
|
793
956
|
|
|
794
957
|
#### FSM پیشرفته: مسیریابی وضعیت با دکوراتور
|
|
@@ -908,22 +1071,97 @@ async def limited_handler(client, message):
|
|
|
908
1071
|
from spluspy.utils import LRUCache
|
|
909
1072
|
|
|
910
1073
|
cache = LRUCache(maxsize=1000, ttl=300) # TTL ۵ دقیقهای
|
|
911
|
-
cache.set("
|
|
912
|
-
|
|
913
|
-
|
|
1074
|
+
cache.set("key", "value")
|
|
1075
|
+
value = cache.get("key")
|
|
1076
|
+
stats = cache.stats() # {'hits': 42, 'misses': 3}
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
### پاسخ خودکار AFK
|
|
1080
|
+
|
|
1081
|
+
```python
|
|
1082
|
+
from spluspy import Client, filters
|
|
1083
|
+
from spluspy.afk import AfkManager
|
|
1084
|
+
|
|
1085
|
+
bot = Client("my_account")
|
|
1086
|
+
afk = AfkManager(bot, message="الان AFK هستم. زود برمیگردم!")
|
|
1087
|
+
|
|
1088
|
+
@bot.on_message(filters.command("afk"))
|
|
1089
|
+
async def set_afk(client, message):
|
|
1090
|
+
afk.set_afk(True, reason="ناهار")
|
|
1091
|
+
await message.reply("الان AFK هستم!")
|
|
1092
|
+
|
|
1093
|
+
@bot.on_message(filters.command("back"))
|
|
1094
|
+
async def unset_afk(client, message):
|
|
1095
|
+
afk.set_afk(False)
|
|
1096
|
+
await message.reply(f"برگشتم! {afk.total_replies} پاسخ خودکار ارسال شد.")
|
|
1097
|
+
|
|
1098
|
+
@bot.on_message(filters.private & filters.incoming)
|
|
1099
|
+
async def auto_reply(client, message):
|
|
1100
|
+
if afk.is_afk:
|
|
1101
|
+
await afk.handle(message)
|
|
914
1102
|
```
|
|
915
1103
|
|
|
916
1104
|
### مدیریت چت
|
|
917
1105
|
|
|
918
1106
|
```python
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
await
|
|
924
|
-
await
|
|
925
|
-
await
|
|
926
|
-
await
|
|
1107
|
+
from spluspy.admin import ChatAdmin
|
|
1108
|
+
|
|
1109
|
+
admin = ChatAdmin(bot)
|
|
1110
|
+
|
|
1111
|
+
await admin.ban_user(chat_id, user_id) # مسدود کردن
|
|
1112
|
+
await admin.unban_user(chat_id, user_id) # رفع مسدودیت
|
|
1113
|
+
await admin.mute_user(chat_id, user_id) # بیصدا کردن
|
|
1114
|
+
await admin.unmute_user(chat_id, user_id) # رفع بیصدایی
|
|
1115
|
+
await admin.pin_message(chat_id, message) # سنجاق کردن
|
|
1116
|
+
await admin.unpin_message(chat_id, message) # رفع سنجاق
|
|
1117
|
+
await admin.unpin_all(chat_id) # رفع همه سنجاقها
|
|
1118
|
+
await admin.purge_messages(chat_id, limit=100) # پاکسازی پیامها
|
|
1119
|
+
|
|
1120
|
+
# عملیات دستهای
|
|
1121
|
+
await admin.bulk_action(chat_id, "ban", [user_id1, user_id2])
|
|
1122
|
+
|
|
1123
|
+
# لاگ مدیریتی
|
|
1124
|
+
events = await admin.get_admin_log(chat_id, limit=50)
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
### آینهسازی پیام
|
|
1128
|
+
|
|
1129
|
+
```python
|
|
1130
|
+
from spluspy.mirror import MessageMirror
|
|
1131
|
+
|
|
1132
|
+
mirror = MessageMirror(bot)
|
|
1133
|
+
|
|
1134
|
+
# افزودن مسیر آینهسازی
|
|
1135
|
+
mirror.add_route(
|
|
1136
|
+
source=-1001234567890,
|
|
1137
|
+
targets=[-1009876543210, -1001112223334],
|
|
1138
|
+
strip_forward=True,
|
|
1139
|
+
strip_sender=False,
|
|
1140
|
+
add_prefix="[Mirror]"
|
|
1141
|
+
)
|
|
1142
|
+
|
|
1143
|
+
# یا به صورت تدریجی
|
|
1144
|
+
mirror.add_source(-1001234567890)
|
|
1145
|
+
mirror.add_target(-1009876543210)
|
|
1146
|
+
|
|
1147
|
+
await mirror.start()
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
### زمانبند
|
|
1151
|
+
|
|
1152
|
+
```python
|
|
1153
|
+
from spluspy.scheduler.scheduler import MessageScheduler
|
|
1154
|
+
|
|
1155
|
+
scheduler = MessageScheduler(bot)
|
|
1156
|
+
|
|
1157
|
+
# ارسال پیام هر ساعت
|
|
1158
|
+
scheduler.schedule_interval("hourly_greeting", chat_id, "سلام!", interval=3600)
|
|
1159
|
+
|
|
1160
|
+
# ارسال پیام با تاخیر
|
|
1161
|
+
scheduler.schedule_once("reminder", chat_id, "فراموش نکن!", delay=300)
|
|
1162
|
+
|
|
1163
|
+
# لغو وظیفه زمانبندی شده
|
|
1164
|
+
scheduler.cancel("hourly_greeting")
|
|
927
1165
|
```
|
|
928
1166
|
|
|
929
1167
|
### مدیریت خطا
|
|
@@ -960,14 +1198,14 @@ bot.on_error(error_handler.build())
|
|
|
960
1198
|
|
|
961
1199
|
```python
|
|
962
1200
|
# ارسال چندین پیام
|
|
963
|
-
|
|
964
|
-
|
|
1201
|
+
messages = ["سلام ۱", "سلام ۲", "سلام ۳"]
|
|
1202
|
+
results = await bot.batch_send(chat_id, messages)
|
|
965
1203
|
|
|
966
1204
|
# حذف چندین پیام
|
|
967
|
-
await bot.batch_delete(chat_id, [
|
|
1205
|
+
await bot.batch_delete(chat_id, [msg1, msg2, msg3])
|
|
968
1206
|
|
|
969
1207
|
# فوروارد چندین پیام
|
|
970
|
-
await bot.batch_forward(chat_id, [
|
|
1208
|
+
await bot.batch_forward(chat_id, [msg1, msg2])
|
|
971
1209
|
```
|
|
972
1210
|
|
|
973
1211
|
### انتقال فایل با پیشرفت
|
|
@@ -989,25 +1227,46 @@ await message.download(progress=tracker)
|
|
|
989
1227
|
# اجرای ربات
|
|
990
1228
|
spluspy run bot.py
|
|
991
1229
|
|
|
1230
|
+
# اجرا با نشست سفارشی
|
|
1231
|
+
spluspy run bot.py --session my_bot
|
|
1232
|
+
|
|
992
1233
|
# اطلاعات نشست
|
|
993
|
-
spluspy session-info
|
|
1234
|
+
spluspy session-info my_session.session
|
|
994
1235
|
|
|
995
1236
|
# نمایش نسخه
|
|
996
1237
|
spluspy version
|
|
997
1238
|
|
|
998
|
-
# اعتبارسنجی
|
|
999
|
-
spluspy validate
|
|
1239
|
+
# اعتبارسنجی اسکریپت ربات
|
|
1240
|
+
spluspy validate bot.py
|
|
1000
1241
|
```
|
|
1001
1242
|
|
|
1002
1243
|
### Docker
|
|
1003
1244
|
|
|
1004
1245
|
```dockerfile
|
|
1005
1246
|
FROM python:3.12-slim
|
|
1247
|
+
|
|
1006
1248
|
WORKDIR /app
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1249
|
+
|
|
1250
|
+
# نصب وابستگیهای سیستمی
|
|
1251
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
1252
|
+
gcc \
|
|
1253
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
1254
|
+
|
|
1255
|
+
# نصب spluspy
|
|
1256
|
+
RUN pip install --no-cache-dir spluspy[all]
|
|
1257
|
+
|
|
1258
|
+
# کپی اسکریپت ربات
|
|
1259
|
+
COPY bot.py .
|
|
1260
|
+
|
|
1261
|
+
# اجرای ربات
|
|
1262
|
+
CMD ["python", "bot.py"]
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
ساخت و اجرا:
|
|
1266
|
+
|
|
1267
|
+
```bash
|
|
1268
|
+
docker build -t my-spluspy-bot .
|
|
1269
|
+
docker run -v ./sessions:/app/sessions my-spluspy-bot
|
|
1011
1270
|
```
|
|
1012
1271
|
|
|
1013
1272
|
### ساختار پروژه
|
|
@@ -1019,8 +1278,13 @@ spluspy/
|
|
|
1019
1278
|
├── cli.py # نقطه ورود CLI
|
|
1020
1279
|
├── config.py # پیکربندی
|
|
1021
1280
|
├── compat.py # لایه سازگاری
|
|
1281
|
+
├── afk.py # پاسخگوی خودکار AFK
|
|
1282
|
+
├── admin.py # مدیریت چت
|
|
1283
|
+
├── mirror.py # موتور آینهسازی پیام
|
|
1022
1284
|
├── client/ # کلاینت و API مکالمه
|
|
1023
|
-
├──
|
|
1285
|
+
│ ├── client.py # کلاس اصلی Client
|
|
1286
|
+
│ └── conversation.py # API مکالمه
|
|
1287
|
+
├── models/ # مدلهای دامنه (Message, User, Chat, Media, و غیره)
|
|
1024
1288
|
├── events/ # انواع رویداد و بیلدرها
|
|
1025
1289
|
├── filters/ # فیلترهای قابل ترکیب پیام
|
|
1026
1290
|
├── errors/ # سلسله مراتب استثنای سفارشی
|
|
@@ -1032,7 +1296,34 @@ spluspy/
|
|
|
1032
1296
|
├── fsm/ # ماشین حالت محدود
|
|
1033
1297
|
├── scheduler/ # زمانبند وظایف
|
|
1034
1298
|
├── utils/ # لاگر، کش، کمککنندهها
|
|
1035
|
-
|
|
1299
|
+
├── sync/ # کلاینت همگامسازی شده
|
|
1300
|
+
└── _engine/ # موتور MTProto سطح پایین
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
### سلسله مراتب خطاها
|
|
1304
|
+
|
|
1305
|
+
```
|
|
1306
|
+
SplusPyError
|
|
1307
|
+
├── SoroushPlusAPIError
|
|
1308
|
+
│ ├── RPCError
|
|
1309
|
+
│ │ ├── FloodWait
|
|
1310
|
+
│ │ ├── Unauthorized
|
|
1311
|
+
│ │ ├── BadRequest
|
|
1312
|
+
│ │ │ ├── ChatNotFound
|
|
1313
|
+
│ │ │ ├── UserNotFound
|
|
1314
|
+
│ │ │ └── MessageNotFound
|
|
1315
|
+
│ │ └── ...
|
|
1316
|
+
│ ├── SessionExpiredError
|
|
1317
|
+
│ └── SessionError
|
|
1318
|
+
├── AuthError
|
|
1319
|
+
├── ValidationError
|
|
1320
|
+
├── JoinChatError
|
|
1321
|
+
│ ├── InvalidInviteLinkError
|
|
1322
|
+
│ ├── InviteLinkExpiredError
|
|
1323
|
+
│ ├── ChatFullError
|
|
1324
|
+
│ ├── ChatDeactivatedError
|
|
1325
|
+
│ └── MembershipRequiredError
|
|
1326
|
+
└── FloodWaitError (محدودیت نرخ)
|
|
1036
1327
|
```
|
|
1037
1328
|
|
|
1038
1329
|
---
|
|
@@ -1043,17 +1334,47 @@ spluspy/
|
|
|
1043
1334
|
|
|
1044
1335
|
1. Fork the repository
|
|
1045
1336
|
2. Create a feature branch (`git checkout -b feature/your-feature`)
|
|
1046
|
-
3.
|
|
1047
|
-
|
|
1048
|
-
|
|
1337
|
+
3. Set up the development environment:
|
|
1338
|
+
```bash
|
|
1339
|
+
python -m venv venv
|
|
1340
|
+
source venv/bin/activate
|
|
1341
|
+
pip install -e ".[dev]"
|
|
1342
|
+
```
|
|
1343
|
+
4. Make your changes
|
|
1344
|
+
5. Run linting and formatting:
|
|
1345
|
+
```bash
|
|
1346
|
+
ruff check spluspy/
|
|
1347
|
+
black spluspy/
|
|
1348
|
+
```
|
|
1349
|
+
6. Run type checking:
|
|
1350
|
+
```bash
|
|
1351
|
+
mypy spluspy/
|
|
1352
|
+
```
|
|
1353
|
+
7. Run tests: `pytest`
|
|
1354
|
+
8. Submit a pull request
|
|
1049
1355
|
|
|
1050
1356
|
### فارسی
|
|
1051
1357
|
|
|
1052
1358
|
1. مخزن را Fork کنید
|
|
1053
1359
|
2. شاخه ویژگی بسازید (`git checkout -b feature/your-feature`)
|
|
1054
|
-
3.
|
|
1055
|
-
|
|
1056
|
-
|
|
1360
|
+
3. محیط توسعه را راهاندازی کنید:
|
|
1361
|
+
```bash
|
|
1362
|
+
python -m venv venv
|
|
1363
|
+
source venv/bin/activate
|
|
1364
|
+
pip install -e ".[dev]"
|
|
1365
|
+
```
|
|
1366
|
+
4. تغییرات خود را اعمال کنید
|
|
1367
|
+
5. لینتر و فرمتکننده را اجرا کنید:
|
|
1368
|
+
```bash
|
|
1369
|
+
ruff check spluspy/
|
|
1370
|
+
black spluspy/
|
|
1371
|
+
```
|
|
1372
|
+
6. بررسی نوع را اجرا کنید:
|
|
1373
|
+
```bash
|
|
1374
|
+
mypy spluspy/
|
|
1375
|
+
```
|
|
1376
|
+
7. تستها را اجرا کنید: `pytest`
|
|
1377
|
+
8. درخواست Pull ارسال کنید
|
|
1057
1378
|
|
|
1058
1379
|
---
|
|
1059
1380
|
|
|
@@ -1081,4 +1402,4 @@ SPlusPy یک کتابخانه غیررسمی و شخص ثالث است. مسئو
|
|
|
1081
1402
|
|
|
1082
1403
|
**ساخته شده با ❤️ برای جامعه سروش پلاس**
|
|
1083
1404
|
|
|
1084
|
-
</div>
|
|
1405
|
+
</div>
|