maxapi-python 2.3.1__tar.gz → 2.4.0__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.
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/PKG-INFO +3 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/account.rst +10 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/files.rst +8 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/chats.rst +34 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/client.rst +24 -2
- maxapi_python-2.4.0/docs/files.rst +174 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/index.rst +1 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/messages.rst +54 -3
- maxapi_python-2.4.0/docs/release-2-4-0.rst +210 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/enums.rst +9 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/index.rst +3 -1
- maxapi_python-2.4.0/docs/types/poll.rst +22 -0
- maxapi_python-2.4.0/docs/types/poll_attachment.rst +6 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/pyproject.toml +6 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/__init__.py +7 -2
- maxapi_python-2.4.0/src/pymax/_data/apk_fingerprints.json +682 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/auth/enums.py +1 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/auth/payloads.py +28 -2
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/auth/service.py +88 -3
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/chats/__init__.py +1 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/chats/enums.py +15 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/chats/payloads.py +16 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/chats/service.py +36 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/messages/payloads.py +12 -4
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/messages/service.py +57 -14
- maxapi_python-2.4.0/src/pymax/api/self/__init__.py +3 -0
- maxapi_python-2.4.0/src/pymax/api/self/enums.py +20 -0
- maxapi_python-2.4.0/src/pymax/api/self/payloads.py +80 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/self/service.py +37 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/session/service.py +21 -8
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/uploads/payloads.py +6 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/uploads/service.py +198 -21
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/app.py +69 -15
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/base.py +8 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/client_web.py +2 -2
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/config.py +44 -7
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/connection.py +29 -18
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/enums.py +1 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/mapping.py +3 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/resolvers.py +7 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/__init__.py +4 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/video.py +58 -0
- maxapi_python-2.4.0/src/pymax/files/voice.py +39 -0
- maxapi_python-2.4.0/src/pymax/fingerprint/__init__.py +1 -0
- maxapi_python-2.4.0/src/pymax/fingerprint/fingerprint.py +47 -0
- maxapi_python-2.4.0/src/pymax/fingerprint/models.py +11 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/auth.py +4 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/bots.py +3 -3
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/chat.py +38 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/message.py +40 -11
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/self.py +25 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/enums.py +13 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/tcp/payload.py +21 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/transport/tcp.py +6 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/transport/websocket.py +6 -3
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/__init__.py +2 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/__init__.py +2 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/enums.py +17 -1
- maxapi_python-2.4.0/src/pymax/types/domain/attachments/poll.py +111 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/sticker.py +1 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/video.py +29 -8
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/chat.py +9 -9
- maxapi_python-2.4.0/src/pymax/types/domain/handshake.py +16 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/login.py +30 -1
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/message.py +21 -20
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/user.py +1 -3
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/__init__.py +1 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/reaction.py +2 -2
- maxapi_python-2.4.0/src/pymax/types/events/voice.py +5 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/api/test_auth_service.py +175 -2
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/api/test_chat_user_self_session_services.py +42 -4
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/api/test_message_service.py +64 -6
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/api/test_upload_service.py +67 -4
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/app/test_app_runtime.py +207 -6
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/conftest.py +13 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/connection/test_connection.py +43 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/connection/test_readers_and_transports.py +31 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/dispatch/test_dispatcher.py +8 -0
- maxapi_python-2.4.0/tests/domain/test_login_models.py +63 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/domain/test_message_models.py +36 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/files/test_files_and_formatting.py +5 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/protocol/test_protocols.py +26 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/uv.lock +17 -1
- maxapi_python-2.3.1/docs/files.rst +0 -117
- maxapi_python-2.3.1/src/pymax/api/self/__init__.py +0 -2
- maxapi_python-2.3.1/src/pymax/api/self/enums.py +0 -11
- maxapi_python-2.3.1/src/pymax/api/self/payloads.py +0 -41
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/ISSUE_TEMPLATE/refactor.md +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/pull_request_template.md +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/workflows/publish.yml +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.github/workflows/tests.yml +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.gitignore +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/.pre-commit-config.yaml +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/LICENSE +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/README.md +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/_static/.gitkeep +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/auth.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/client-client.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/client-config.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/client-web.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/client.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/api/router.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/auth.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/conf.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/examples.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/faq.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/formatting.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/getting-started.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-1-0.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-1-1.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-1-2.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-1-3.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-2-0.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-3-0.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/release-2-3-1.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/router.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/troubleshooting.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/audio_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/call_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/chat.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/contact_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/contact_info.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/control_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/element.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/file_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/folder.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/folder_list.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/folder_update.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/inline_keyboard_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/message.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/message_delete_event.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/message_read_event.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/name.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/photo_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/presence_event.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/profile.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/reaction_counter.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/reaction_info.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/reaction_update_event.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/read_state.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/session.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/share_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/sticker_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/sync_overrides.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/sync_state.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/typing_event.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/user.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/types/video_attachment.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/docs/users.rst +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/auth/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/auth/types.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/binding.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/bots/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/bots/payloads.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/bots/service.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/facade.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/messages/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/messages/enums.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/response.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/session/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/session/enums.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/session/payloads.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/uploads/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/uploads/models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/users/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/users/enums.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/users/payloads.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/api/users/service.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/email.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/providers.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/qr.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/service.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/auth/sms.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/client.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/pending.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/readers/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/readers/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/readers/tcp.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/connection/readers/ws.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/dispatcher.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/dispatch/router.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/exceptions.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/file.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/photo.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/files/static.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/formatting/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/formatting/markdown.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/protocol.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/infra/user.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/logging.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/tcp/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/tcp/compression.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/tcp/framing.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/tcp/protocol.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/ws/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/protocol/ws/protocol.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/py.typed +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/routers.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/session/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/session/models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/session/protocol.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/session/store.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/telemetry/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/telemetry/navigation.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/telemetry/payloads.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/telemetry/service.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/transport/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/transport/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/audio.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/call.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/contact.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/control.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/file.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/keyboards/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/keyboards/inline.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/photo.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/share.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/attachments/unknown.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/auth.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/base.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/bots.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/element.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/enums.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/error.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/folder.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/member.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/name.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/presence.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/profile.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/session.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/domain/sync.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/file.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/mark.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/message.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/presence.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/typing.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/src/pymax/types/events/video.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/__init__.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/auth/test_auth_flows.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/domain/test_bound_models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/domain/test_user_models.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/session/test_store.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/telemetry/test_telemetry.py +0 -0
- {maxapi_python-2.3.1 → maxapi_python-2.4.0}/tests/test_logging.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maxapi-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Python wrapper для API мессенджера Max
|
|
5
5
|
Project-URL: Homepage, https://github.com/MaxApiTeam/PyMax
|
|
6
6
|
Project-URL: Repository, https://github.com/MaxApiTeam/PyMax
|
|
@@ -32,6 +32,8 @@ Requires-Dist: python-socks[asyncio]>=2.8.1
|
|
|
32
32
|
Requires-Dist: qrcode>=8.2
|
|
33
33
|
Requires-Dist: websockets>=16.0
|
|
34
34
|
Requires-Dist: zstandard>=0.25.0
|
|
35
|
+
Provides-Extra: video
|
|
36
|
+
Requires-Dist: tinytag>=2.2.1; extra == 'video'
|
|
35
37
|
Description-Content-Type: text/markdown
|
|
36
38
|
|
|
37
39
|
# PyMax
|
|
@@ -53,6 +53,16 @@ Account
|
|
|
53
53
|
photo_token="PHOTO_TOKEN",
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
+
Статус присутствия
|
|
57
|
+
------------------
|
|
58
|
+
|
|
59
|
+
``set_presence()`` меняет статус, который будет использован при следующем
|
|
60
|
+
login или ping:
|
|
61
|
+
|
|
62
|
+
.. code-block:: python
|
|
63
|
+
|
|
64
|
+
client.set_presence(online=True)
|
|
65
|
+
|
|
56
66
|
Папки чатов
|
|
57
67
|
-----------
|
|
58
68
|
|
|
@@ -90,6 +90,40 @@ login/sync, а также методы для загрузки, создания
|
|
|
90
90
|
``invite()`` работает только для групп и каналов. Для личного диалога тип чата
|
|
91
91
|
не подходит, и метод завершится ошибкой.
|
|
92
92
|
|
|
93
|
+
Участники и администраторы канала
|
|
94
|
+
---------------------------------
|
|
95
|
+
|
|
96
|
+
``get_chat_members()`` возвращает одну страницу участников и маркер следующей:
|
|
97
|
+
|
|
98
|
+
.. code-block:: python
|
|
99
|
+
|
|
100
|
+
members, marker = await client.get_chat_members(chat_id=123456, count=50)
|
|
101
|
+
for member in members:
|
|
102
|
+
print(member.contact.id)
|
|
103
|
+
|
|
104
|
+
if marker:
|
|
105
|
+
next_members, marker = await client.get_chat_members(
|
|
106
|
+
chat_id=123456,
|
|
107
|
+
marker=marker,
|
|
108
|
+
count=50,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
Назначить администратора канала можно с явным набором прав:
|
|
112
|
+
|
|
113
|
+
.. code-block:: python
|
|
114
|
+
|
|
115
|
+
from pymax.api.chats import ChannelPermissions
|
|
116
|
+
|
|
117
|
+
await client.add_admin(
|
|
118
|
+
chat_id=123456,
|
|
119
|
+
user_id=111,
|
|
120
|
+
permissions=[
|
|
121
|
+
ChannelPermissions.POST_MESSAGE,
|
|
122
|
+
ChannelPermissions.EDIT_MESSAGE,
|
|
123
|
+
ChannelPermissions.DELETE_MESSAGE,
|
|
124
|
+
],
|
|
125
|
+
)
|
|
126
|
+
|
|
93
127
|
Настройки и профиль группы
|
|
94
128
|
--------------------------
|
|
95
129
|
|
|
@@ -33,6 +33,18 @@ Client
|
|
|
33
33
|
6. Вызывается ``on_start``.
|
|
34
34
|
7. Клиент слушает события до закрытия соединения или отмены задачи.
|
|
35
35
|
|
|
36
|
+
Если ``start()`` запущен отдельной задачей, ``stop()`` штатно закрывает
|
|
37
|
+
соединение и завершает эту задачу без ``CancelledError``:
|
|
38
|
+
|
|
39
|
+
.. code-block:: python
|
|
40
|
+
|
|
41
|
+
import asyncio
|
|
42
|
+
|
|
43
|
+
task = asyncio.create_task(client.start())
|
|
44
|
+
# ... работа приложения ...
|
|
45
|
+
await client.stop()
|
|
46
|
+
await task
|
|
47
|
+
|
|
36
48
|
Данные после login
|
|
37
49
|
------------------
|
|
38
50
|
|
|
@@ -54,6 +66,15 @@ Client
|
|
|
54
66
|
Для актуализации используйте явные методы: ``fetch_chats()``, ``get_chat()``,
|
|
55
67
|
``get_users()``, ``fetch_users()`` и ``fetch_history()``.
|
|
56
68
|
|
|
69
|
+
После handshake можно проверить, требует ли Max обновления версии приложения:
|
|
70
|
+
|
|
71
|
+
.. code-block:: python
|
|
72
|
+
|
|
73
|
+
@client.on_start()
|
|
74
|
+
async def on_start(client: Client) -> None:
|
|
75
|
+
if client.is_update_available():
|
|
76
|
+
print("Для выбранной версии приложения доступно обновление")
|
|
77
|
+
|
|
57
78
|
Создание клиента
|
|
58
79
|
----------------
|
|
59
80
|
|
|
@@ -300,13 +321,14 @@ Debug-логи показывают handshake, login, входящие собы
|
|
|
300
321
|
Клиент собирает несколько API-направлений:
|
|
301
322
|
|
|
302
323
|
Сообщения
|
|
303
|
-
``send_message()``, ``forward_message()``, ``fetch_history()``,
|
|
324
|
+
``send_message()``, ``forward_message()``, ``fetch_history()``, ``vote_poll()``,
|
|
304
325
|
``delete_message()``, ``pin_message()``, ``read_message()``, реакции и
|
|
305
326
|
получение URL для входящих файлов/видео.
|
|
306
327
|
|
|
307
328
|
Чаты
|
|
308
329
|
``get_chat()``, ``fetch_chats()``, создание групп, invite-ссылки,
|
|
309
|
-
участники, настройки групп, удаление чатов и
|
|
330
|
+
участники, назначение администраторов, настройки групп, удаление чатов и
|
|
331
|
+
выход из групп/каналов.
|
|
310
332
|
|
|
311
333
|
Пользователи
|
|
312
334
|
``get_user()``, ``get_users()``, ``fetch_users()``, ``search_by_phone()``,
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Files
|
|
2
|
+
=====
|
|
3
|
+
|
|
4
|
+
Что это
|
|
5
|
+
-------
|
|
6
|
+
|
|
7
|
+
Для отправки вложений PyMax использует пять основных классов:
|
|
8
|
+
|
|
9
|
+
``Photo``
|
|
10
|
+
Фото. Проверяет расширение и MIME-тип.
|
|
11
|
+
|
|
12
|
+
``Video``
|
|
13
|
+
Видео. Загружается чанками и ждет событие готовности от Max.
|
|
14
|
+
|
|
15
|
+
``File``
|
|
16
|
+
Обычный файл. Тоже загружается чанками и ждет событие готовности.
|
|
17
|
+
|
|
18
|
+
``Voice``
|
|
19
|
+
Голосовое сообщение. Поддерживается только формат OGG; PyMax не
|
|
20
|
+
конвертирует другие аудиоформаты.
|
|
21
|
+
|
|
22
|
+
``VideoNote``
|
|
23
|
+
Круглое видеосообщение. Можно передать длительность вручную или установить
|
|
24
|
+
extra ``video`` для автоматического определения.
|
|
25
|
+
|
|
26
|
+
Как отправить файл
|
|
27
|
+
------------------
|
|
28
|
+
|
|
29
|
+
.. code-block:: python
|
|
30
|
+
|
|
31
|
+
import asyncio
|
|
32
|
+
|
|
33
|
+
from pymax import Client, File, Photo, Video, VideoNote, Voice
|
|
34
|
+
|
|
35
|
+
client = Client(phone="+79990000000", work_dir="cache")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@client.on_start()
|
|
39
|
+
async def send_files(client: Client) -> None:
|
|
40
|
+
chat = await client.get_chat(123456)
|
|
41
|
+
|
|
42
|
+
await chat.answer(
|
|
43
|
+
text="Фото",
|
|
44
|
+
attachments=[Photo(path="image.jpg")],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
await chat.answer(
|
|
48
|
+
text="Документ",
|
|
49
|
+
attachments=[File(path="report.pdf")],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
await chat.answer(
|
|
53
|
+
text="Видео",
|
|
54
|
+
attachments=[Video(path="clip.mp4")],
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
await chat.answer(attachments=[Voice(path="voice.ogg")])
|
|
58
|
+
await chat.answer(
|
|
59
|
+
attachments=[VideoNote(path="circle.mp4", duration=4200)]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
asyncio.run(client.start())
|
|
64
|
+
|
|
65
|
+
Источники данных
|
|
66
|
+
----------------
|
|
67
|
+
|
|
68
|
+
Можно передать ровно один источник:
|
|
69
|
+
|
|
70
|
+
.. code-block:: python
|
|
71
|
+
|
|
72
|
+
Photo(path="image.jpg")
|
|
73
|
+
File(url="https://example.com/report.pdf")
|
|
74
|
+
Video(raw=b"...", name="clip.mp4")
|
|
75
|
+
Voice(path="voice.ogg")
|
|
76
|
+
VideoNote(path="circle.mp4", duration=4200)
|
|
77
|
+
|
|
78
|
+
Для ``raw`` обязательно указывайте ``name``. Для ``File``, ``Video``,
|
|
79
|
+
``Voice`` и ``VideoNote`` имя берется из ``path`` или ``url``, если не
|
|
80
|
+
передано явно.
|
|
81
|
+
|
|
82
|
+
Если длительность ``VideoNote`` не передана, установите дополнительную
|
|
83
|
+
зависимость:
|
|
84
|
+
|
|
85
|
+
.. code-block:: console
|
|
86
|
+
|
|
87
|
+
uv add "maxapi-python[video]"
|
|
88
|
+
|
|
89
|
+
Формат Voice и VideoNote
|
|
90
|
+
------------------------
|
|
91
|
+
|
|
92
|
+
Для ``Voice`` используйте готовый OGG-файл. Простого переименования MP3, WAV
|
|
93
|
+
или другого аудиофайла в ``.ogg`` недостаточно: PyMax загружает исходные байты
|
|
94
|
+
без перекодирования.
|
|
95
|
+
|
|
96
|
+
``VideoNote`` также не перекодирует видео. Для совместимости с официальным
|
|
97
|
+
клиентом 26.21.1 рекомендуется следующий формат:
|
|
98
|
+
|
|
99
|
+
* контейнер MP4;
|
|
100
|
+
* видео H.264/AVC, 480x480, 30 FPS и bitrate около 1 024 000 bit/s;
|
|
101
|
+
* pixel format ``yuv420p`` при подготовке через FFmpeg;
|
|
102
|
+
* ключевой кадр примерно раз в секунду, то есть GOP около 30 кадров;
|
|
103
|
+
* аудио AAC в том же MP4-контейнере;
|
|
104
|
+
* длительность до 60 секунд.
|
|
105
|
+
|
|
106
|
+
Официальный клиент задает квадратное разрешение, фиксированные 30 FPS и
|
|
107
|
+
максимальную длительность через server config. Нижняя граница в одну секунду
|
|
108
|
+
не является подтвержденным ограничением upload API, поэтому PyMax ее не
|
|
109
|
+
проверяет.
|
|
110
|
+
|
|
111
|
+
Поворот лучше физически применить при перекодировании и убрать rotation
|
|
112
|
+
metadata: так файл меньше зависит от того, как конкретный клиент обработает
|
|
113
|
+
orientation hint. H.264 profile и level специально фиксировать не требуется.
|
|
114
|
+
``faststart`` официальный recorder явно не включает; при самостоятельной
|
|
115
|
+
подготовке файла его можно использовать, но для PyMax это не обязательное
|
|
116
|
+
условие.
|
|
117
|
+
|
|
118
|
+
Как работает upload
|
|
119
|
+
-------------------
|
|
120
|
+
|
|
121
|
+
1. PyMax запрашивает у Max временный upload URL.
|
|
122
|
+
2. Читает файл из ``path``, ``url`` или ``raw``.
|
|
123
|
+
3. Загружает данные HTTP-запросом.
|
|
124
|
+
4. Для ``File``, ``Video``, ``Voice`` и ``VideoNote`` ждет служебное событие
|
|
125
|
+
готовности до 60 секунд.
|
|
126
|
+
5. Подставляет token/file_id/video_id в отправляемое сообщение.
|
|
127
|
+
|
|
128
|
+
Фото проходит проще: после HTTP-upload PyMax сразу достает token из ответа.
|
|
129
|
+
|
|
130
|
+
Скачать входящий файл
|
|
131
|
+
---------------------
|
|
132
|
+
|
|
133
|
+
``FileAttachment`` содержит ID, но для скачивания нужен временный URL:
|
|
134
|
+
|
|
135
|
+
.. code-block:: python
|
|
136
|
+
|
|
137
|
+
from pymax import Client, Message
|
|
138
|
+
from pymax.types.domain import FileAttachment
|
|
139
|
+
|
|
140
|
+
@client.on_message()
|
|
141
|
+
async def on_message(message: Message, client: Client) -> None:
|
|
142
|
+
if message.chat_id is None:
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
for attach in message.attaches:
|
|
146
|
+
if isinstance(attach, FileAttachment):
|
|
147
|
+
info = await client.get_file_by_id(
|
|
148
|
+
chat_id=message.chat_id,
|
|
149
|
+
message_id=message.id,
|
|
150
|
+
file_id=attach.file_id,
|
|
151
|
+
)
|
|
152
|
+
print(info.url if info else "URL не получен")
|
|
153
|
+
|
|
154
|
+
Частые ошибки
|
|
155
|
+
-------------
|
|
156
|
+
|
|
157
|
+
``ValueError: Only one of raw, url or path must be provided``
|
|
158
|
+
Передайте только один источник файла.
|
|
159
|
+
|
|
160
|
+
``ValueError: Name must be provided for raw data``
|
|
161
|
+
Для bytes укажите имя: ``File(raw=data, name="file.bin")``.
|
|
162
|
+
|
|
163
|
+
``Invalid photo extension``
|
|
164
|
+
``Photo`` принимает ``.jpg``, ``.jpeg``, ``.png``, ``.gif``, ``.webp`` и
|
|
165
|
+
``.bmp``.
|
|
166
|
+
|
|
167
|
+
``UploadError``
|
|
168
|
+
Upload-сервис не получил нужный ответ от Max. Включите ``DEBUG``-логи:
|
|
169
|
+
часто причина в недоступном URL, неверном размере файла, timeout или в том,
|
|
170
|
+
что событие готовности файла не пришло за 60 секунд.
|
|
171
|
+
|
|
172
|
+
``Automatic video duration detection requires the 'video' extra``
|
|
173
|
+
Передайте ``duration`` в миллисекундах или установите
|
|
174
|
+
``maxapi-python[video]``.
|
|
@@ -83,6 +83,57 @@ Messages
|
|
|
83
83
|
source_chat_id=123456,
|
|
84
84
|
)
|
|
85
85
|
|
|
86
|
+
Опросы
|
|
87
|
+
------
|
|
88
|
+
|
|
89
|
+
Опрос можно отправить без текста. Настройки объединяются оператором ``|``:
|
|
90
|
+
|
|
91
|
+
.. code-block:: python
|
|
92
|
+
|
|
93
|
+
from pymax.types import Poll, PollAnswer, PollFlags
|
|
94
|
+
|
|
95
|
+
await client.send_message(
|
|
96
|
+
chat_id=123456,
|
|
97
|
+
attachments=[
|
|
98
|
+
Poll(
|
|
99
|
+
title="Какой вариант выбрать?",
|
|
100
|
+
answers=[
|
|
101
|
+
PollAnswer(text="Первый"),
|
|
102
|
+
PollAnswer(text="Второй"),
|
|
103
|
+
],
|
|
104
|
+
settings=(
|
|
105
|
+
PollFlags.FLAG_SETTINGS_ANONYMOUS
|
|
106
|
+
| PollFlags.FLAG_SETTINGS_REVOTE
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
Для голосования нужны ID сообщения, опроса и вариантов из входящего
|
|
113
|
+
``PollAttachment``:
|
|
114
|
+
|
|
115
|
+
.. code-block:: python
|
|
116
|
+
|
|
117
|
+
from pymax import Message
|
|
118
|
+
from pymax.types import PollAttachment
|
|
119
|
+
|
|
120
|
+
@client.on_message()
|
|
121
|
+
async def vote(message: Message, client: Client) -> None:
|
|
122
|
+
if message.chat_id is None:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
for attach in message.attaches:
|
|
126
|
+
if isinstance(attach, PollAttachment):
|
|
127
|
+
answer_id = attach.answers[0].answer_id
|
|
128
|
+
if answer_id is not None:
|
|
129
|
+
state = await client.vote_poll(
|
|
130
|
+
chat_id=message.chat_id,
|
|
131
|
+
message_id=message.id,
|
|
132
|
+
poll_id=attach.poll_id,
|
|
133
|
+
answer_ids=[answer_id],
|
|
134
|
+
)
|
|
135
|
+
print(state.total)
|
|
136
|
+
|
|
86
137
|
Ответ, реакции, удаление и прочтение
|
|
87
138
|
----------------------------------------
|
|
88
139
|
|
|
@@ -147,7 +198,7 @@ Messages
|
|
|
147
198
|
.. code-block:: python
|
|
148
199
|
|
|
149
200
|
history = await client.fetch_history(chat_id=123456, backward=50)
|
|
150
|
-
for message in history
|
|
201
|
+
for message in history:
|
|
151
202
|
print(message.id, message.text)
|
|
152
203
|
|
|
153
204
|
``fetch_history()`` принимает ``item_type``. По умолчанию используются обычные
|
|
@@ -178,8 +229,8 @@ Max присылает разные формы событий. Некоторы
|
|
|
178
229
|
--------
|
|
179
230
|
|
|
180
231
|
Входящие вложения лежат в ``message.attaches``. Тип вложения определяется по
|
|
181
|
-
полю ``type``: фото, видео, файл, стикер, аудио, контакт, звонок, share
|
|
182
|
-
inline-клавиатура.
|
|
232
|
+
полю ``type``: фото, видео, файл, стикер, аудио, опрос, контакт, звонок, share
|
|
233
|
+
или inline-клавиатура.
|
|
183
234
|
|
|
184
235
|
.. code-block:: python
|
|
185
236
|
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
PyMax 2.4.0
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
Версия 2.4.0 добавляет опросы, голосовые сообщения, кружки, настройки
|
|
5
|
+
приватности и новые методы управления чатами. Одновременно уточнены контракты
|
|
6
|
+
существующих методов и исправлены проблемы с lifecycle клиента, повторной
|
|
7
|
+
авторизацией и WebSocket.
|
|
8
|
+
|
|
9
|
+
Ниже перечислены изменения относительно ``2.3.1``, которые важны при
|
|
10
|
+
использовании библиотеки и обновлении существующего кода.
|
|
11
|
+
|
|
12
|
+
Новый публичный API
|
|
13
|
+
-------------------
|
|
14
|
+
|
|
15
|
+
Опросы
|
|
16
|
+
~~~~~~
|
|
17
|
+
|
|
18
|
+
Добавлены модели ``Poll``, ``PollAnswer`` и ``PollFlags`` для создания
|
|
19
|
+
опросов. Опрос отправляется обычным ``send_message()`` и может быть
|
|
20
|
+
единственным вложением без текста:
|
|
21
|
+
|
|
22
|
+
.. code-block:: python
|
|
23
|
+
|
|
24
|
+
from pymax.types import Poll, PollAnswer, PollFlags
|
|
25
|
+
|
|
26
|
+
message = await client.send_message(
|
|
27
|
+
chat_id=123456,
|
|
28
|
+
attachments=[
|
|
29
|
+
Poll(
|
|
30
|
+
title="Выберите вариант",
|
|
31
|
+
answers=[
|
|
32
|
+
PollAnswer(text="Первый"),
|
|
33
|
+
PollAnswer(text="Второй"),
|
|
34
|
+
],
|
|
35
|
+
settings=PollFlags.FLAG_SETTINGS_REVOTE,
|
|
36
|
+
)
|
|
37
|
+
],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
Для голосования добавлен метод:
|
|
41
|
+
|
|
42
|
+
``await client.vote_poll(chat_id, message_id, poll_id, answer_ids) -> PollState``
|
|
43
|
+
|
|
44
|
+
Входящий опрос представлен моделью ``PollAttachment``. Она содержит
|
|
45
|
+
``poll_id``, варианты ответа и текущее состояние ``PollState`` с
|
|
46
|
+
типизированными результатами и голосами.
|
|
47
|
+
|
|
48
|
+
Голосовые сообщения и кружки
|
|
49
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
50
|
+
|
|
51
|
+
Добавлены два типа отправляемых вложений:
|
|
52
|
+
|
|
53
|
+
``Voice``
|
|
54
|
+
Голосовое сообщение. Принимает только готовый OGG-файл. PyMax не
|
|
55
|
+
перекодирует MP3, WAV и другие форматы.
|
|
56
|
+
|
|
57
|
+
``VideoNote``
|
|
58
|
+
Круглое видеосообщение. Рекомендуемый формат — MP4 с H.264-видео 480x480,
|
|
59
|
+
30 FPS и AAC-аудио. Длительность передается в миллисекундах через
|
|
60
|
+
``duration``.
|
|
61
|
+
|
|
62
|
+
Оба класса экспортируются из ``pymax`` и передаются в ``attachments``:
|
|
63
|
+
|
|
64
|
+
.. code-block:: python
|
|
65
|
+
|
|
66
|
+
from pymax import VideoNote, Voice
|
|
67
|
+
|
|
68
|
+
await client.send_message(
|
|
69
|
+
chat_id=123456,
|
|
70
|
+
attachments=[Voice(path="voice.ogg")],
|
|
71
|
+
)
|
|
72
|
+
await client.send_message(
|
|
73
|
+
chat_id=123456,
|
|
74
|
+
attachments=[VideoNote(path="circle.mp4", duration=4200)],
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
Если ``duration`` для ``VideoNote`` не указан, PyMax может определить его
|
|
78
|
+
автоматически с необязательной зависимостью ``video``::
|
|
79
|
+
|
|
80
|
+
uv add "maxapi-python[video]"
|
|
81
|
+
|
|
82
|
+
Чаты и состояние аккаунта
|
|
83
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
84
|
+
|
|
85
|
+
.. list-table:: Новые методы
|
|
86
|
+
:header-rows: 1
|
|
87
|
+
:widths: 35 40 25
|
|
88
|
+
|
|
89
|
+
* - Метод
|
|
90
|
+
- Назначение
|
|
91
|
+
- Результат
|
|
92
|
+
* - ``get_chat_members(chat_id, marker=None, count=50)``
|
|
93
|
+
- Получить страницу участников чата. Ненулевой ``marker`` передается в
|
|
94
|
+
следующий вызов.
|
|
95
|
+
- ``tuple[list[Member], int]``
|
|
96
|
+
* - ``add_admin(chat_id, user_id, permissions)``
|
|
97
|
+
- Назначить администратора канала с явным списком
|
|
98
|
+
``ChannelPermissions``.
|
|
99
|
+
- ``None``
|
|
100
|
+
* - ``set_presence(online=...)``
|
|
101
|
+
- Изменить статус, используемый при следующем login или ping.
|
|
102
|
+
- ``None``
|
|
103
|
+
* - ``is_update_available()``
|
|
104
|
+
- Проверить флаг обновления, полученный при handshake.
|
|
105
|
+
- ``bool``
|
|
106
|
+
|
|
107
|
+
Настройки приватности
|
|
108
|
+
~~~~~~~~~~~~~~~~~~~~~
|
|
109
|
+
|
|
110
|
+
Добавлен метод
|
|
111
|
+
``await client.change_profile_settings(settings) -> bool``. Он принимает
|
|
112
|
+
``PrivacySettingsUpdate`` и изменяет только заполненные поля:
|
|
113
|
+
|
|
114
|
+
.. code-block:: python
|
|
115
|
+
|
|
116
|
+
from pymax import PrivacyAccess, PrivacySettingsUpdate
|
|
117
|
+
|
|
118
|
+
await client.change_profile_settings(
|
|
119
|
+
PrivacySettingsUpdate(
|
|
120
|
+
search_by_phone=PrivacyAccess.CONTACTS,
|
|
121
|
+
incoming_calls=PrivacyAccess.ALL,
|
|
122
|
+
chat_invites=PrivacyAccess.NOBODY,
|
|
123
|
+
phone_number_visibility=PrivacyAccess.CONTACTS,
|
|
124
|
+
hide_online_status=True,
|
|
125
|
+
safe_content_only=True,
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
Для настроек доступа используются ``PrivacyAccess.ALL``,
|
|
130
|
+
``PrivacyAccess.CONTACTS`` и ``PrivacyAccess.NOBODY``. После успешного запроса
|
|
131
|
+
PyMax сохраняет новый ``config_hash`` в текущей сессии, поэтому следующая
|
|
132
|
+
авторизация продолжает синхронизацию с актуального состояния.
|
|
133
|
+
|
|
134
|
+
Изменения существующего API
|
|
135
|
+
---------------------------
|
|
136
|
+
|
|
137
|
+
.. list-table:: Изменившиеся контракты
|
|
138
|
+
:header-rows: 1
|
|
139
|
+
:widths: 30 30 40
|
|
140
|
+
|
|
141
|
+
* - API
|
|
142
|
+
- Было в 2.3.1
|
|
143
|
+
- Стало в 2.4.0
|
|
144
|
+
* - ``send_message()`` и ``forward_message()``
|
|
145
|
+
- Возвращаемый тип допускал ``Message | None``.
|
|
146
|
+
- Возвращают ``Message``. Если сервер не прислал обязательный объект
|
|
147
|
+
сообщения, вызов завершается ошибкой.
|
|
148
|
+
* - ``Message.reply()``, ``Message.answer()``, ``Message.forward()`` и
|
|
149
|
+
``Chat.answer()``
|
|
150
|
+
- Bound-методы также имели необязательный возвращаемый тип.
|
|
151
|
+
- Возвращают ``Message`` без лишней проверки на ``None``.
|
|
152
|
+
* - ``send_message()``, ``edit_message()``, ``Message.reply()``,
|
|
153
|
+
``Message.answer()`` и ``Chat.answer()``
|
|
154
|
+
- Для type checker требовался текст.
|
|
155
|
+
- ``text`` может быть ``None``, если переданы вложения. Если нет ни
|
|
156
|
+
текста, ни вложений, выбрасывается ``ValueError``.
|
|
157
|
+
* - ``fetch_history()``
|
|
158
|
+
- При отсутствии сообщений мог вернуть ``None``.
|
|
159
|
+
- Всегда возвращает ``list[Message]``; пустая история — ``[]``.
|
|
160
|
+
* - ``get_bot_init_data()``
|
|
161
|
+
- ``chat_id`` был обязательным.
|
|
162
|
+
- ``chat_id`` необязателен, поэтому метод можно вызвать вне чата.
|
|
163
|
+
* - ``change_profile()``
|
|
164
|
+
- ``photo`` был типизирован как ``Any``.
|
|
165
|
+
- ``photo`` принимает ``Photo | None``.
|
|
166
|
+
|
|
167
|
+
Также исправлены типы частичных моделей протокола. В частности,
|
|
168
|
+
``StickerAttachment.set_id`` теперь имеет тип ``int | None``, а поля неполных
|
|
169
|
+
событий реакций больше не считаются безусловно заполненными.
|
|
170
|
+
|
|
171
|
+
Breaking changes
|
|
172
|
+
----------------
|
|
173
|
+
|
|
174
|
+
Методы и классы из 2.3.1 не удалялись и не переименовывались. Проверить перед
|
|
175
|
+
обновлением нужно два наблюдаемых изменения поведения:
|
|
176
|
+
|
|
177
|
+
* Код, который отличал ``None`` от пустого списка после ``fetch_history()``,
|
|
178
|
+
должен проверять пустоту списка: ``if not history``.
|
|
179
|
+
* Попытка отправить или отредактировать сообщение без текста и без вложений
|
|
180
|
+
теперь сразу завершается ``ValueError``. Сообщения только с вложением
|
|
181
|
+
поддерживаются штатно.
|
|
182
|
+
|
|
183
|
+
Изменения ``Message | None`` на ``Message`` у методов отправки и пересылки —
|
|
184
|
+
уточнение публичного контракта, а не новое успешное значение в runtime.
|
|
185
|
+
Пользователи mypy или Pyright могут удалить лишние проверки результата на
|
|
186
|
+
``None``. При работе со ``StickerAttachment.set_id`` проверка на ``None``,
|
|
187
|
+
наоборот, теперь требуется.
|
|
188
|
+
|
|
189
|
+
Исправления стабильности и совместимости
|
|
190
|
+
----------------------------------------
|
|
191
|
+
|
|
192
|
+
* Если текущую сессию отозвали с другого устройства, ответы
|
|
193
|
+
``FAIL_LOGIN_TOKEN`` и ``FAIL_LOGOUT_ALL`` больше не оставляют клиент в
|
|
194
|
+
цикле переподключений. PyMax удаляет недействительный локальный token и
|
|
195
|
+
запускает авторизацию заново. Закрытие TLS-соединения ограничено timeout,
|
|
196
|
+
поэтому зависший shutdown не блокирует клиент бесконечно.
|
|
197
|
+
* ``stop()`` штатно завершает ожидающий ``start()``. Внешняя отмена задачи при
|
|
198
|
+
этом не поглощается и продолжает распространяться вызывающему коду.
|
|
199
|
+
* WebSocket-клиент использует актуальный endpoint и корректно обрабатывает
|
|
200
|
+
бинарные protocol frames.
|
|
201
|
+
* Mobile login поддерживает двухэтапный LOGIN/LOGIN2. Fingerprint устройства
|
|
202
|
+
выбирается автоматически из данных Android-версий от 26.9.1 до 26.25.0.
|
|
203
|
+
* Handshake без обязательного ``callsSeed`` завершается контролируемой ошибкой,
|
|
204
|
+
а не оставляет клиент в частично инициализированном состоянии.
|
|
205
|
+
* Исправлены очистка ожиданий при ошибках upload, выбор MP4 URL по качеству и
|
|
206
|
+
разбор частичных событий реакций и голосов в опросах.
|
|
207
|
+
|
|
208
|
+
Базовый набор зависимостей не изменился. Extra ``video`` нужен только для
|
|
209
|
+
автоматического определения длительности ``VideoNote``; при явном
|
|
210
|
+
``duration`` он не требуется.
|
|
@@ -19,6 +19,15 @@ Domain enums
|
|
|
19
19
|
.. autoclass:: pymax.types.domain.attachments.enums.TranscriptionStatus
|
|
20
20
|
:members:
|
|
21
21
|
|
|
22
|
+
.. autoclass:: pymax.types.domain.attachments.enums.PollFlags
|
|
23
|
+
:members:
|
|
24
|
+
|
|
25
|
+
Chat API enums
|
|
26
|
+
--------------
|
|
27
|
+
|
|
28
|
+
.. autoclass:: pymax.api.chats.ChannelPermissions
|
|
29
|
+
:members:
|
|
30
|
+
|
|
22
31
|
Client config enums
|
|
23
32
|
-------------------
|
|
24
33
|
|
|
@@ -40,7 +40,7 @@ Types
|
|
|
40
40
|
``ContactInfo``
|
|
41
41
|
Контакт телефонной книги для ``import_contacts()``.
|
|
42
42
|
|
|
43
|
-
``PhotoAttachment``, ``VideoAttachment``, ``FileAttachment`` и другие
|
|
43
|
+
``PhotoAttachment``, ``VideoAttachment``, ``FileAttachment``, ``PollAttachment`` и другие
|
|
44
44
|
Входящие вложения в ``message.attaches``.
|
|
45
45
|
|
|
46
46
|
``SyncState`` и ``SyncOverrides``
|
|
@@ -112,6 +112,8 @@ API reference
|
|
|
112
112
|
control_attachment
|
|
113
113
|
file_attachment
|
|
114
114
|
photo_attachment
|
|
115
|
+
poll
|
|
116
|
+
poll_attachment
|
|
115
117
|
share_attachment
|
|
116
118
|
sticker_attachment
|
|
117
119
|
video_attachment
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Poll
|
|
2
|
+
====
|
|
3
|
+
|
|
4
|
+
.. autoclass:: pymax.types.domain.attachments.poll.Poll
|
|
5
|
+
:members:
|
|
6
|
+
:show-inheritance:
|
|
7
|
+
|
|
8
|
+
.. autoclass:: pymax.types.domain.attachments.poll.PollAnswer
|
|
9
|
+
:members:
|
|
10
|
+
:show-inheritance:
|
|
11
|
+
|
|
12
|
+
.. autoclass:: pymax.types.domain.attachments.poll.PollState
|
|
13
|
+
:members:
|
|
14
|
+
:show-inheritance:
|
|
15
|
+
|
|
16
|
+
.. autoclass:: pymax.types.domain.attachments.poll.PollResult
|
|
17
|
+
:members:
|
|
18
|
+
:show-inheritance:
|
|
19
|
+
|
|
20
|
+
.. autoclass:: pymax.types.domain.attachments.poll.PollVote
|
|
21
|
+
:members:
|
|
22
|
+
:show-inheritance:
|