maxapi-python 2.4.0__tar.gz → 2.4.1__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.
Files changed (272) hide show
  1. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/PKG-INFO +6 -4
  2. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/README.md +4 -2
  3. maxapi_python-2.4.1/TODO.md +44 -0
  4. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/account.rst +2 -3
  5. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/auth.rst +2 -0
  6. maxapi_python-2.4.1/docs/api/client-session.rst +20 -0
  7. maxapi_python-2.4.1/docs/api/client-versions.rst +12 -0
  8. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/client.rst +2 -0
  9. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/auth.rst +24 -0
  10. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/chats.rst +8 -0
  11. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/client.rst +109 -6
  12. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/faq.rst +5 -3
  13. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/files.rst +18 -7
  14. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/index.rst +1 -0
  15. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/messages.rst +69 -5
  16. maxapi_python-2.4.1/docs/release-2-4-1.rst +103 -0
  17. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/troubleshooting.rst +4 -3
  18. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/enums.rst +9 -0
  19. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/index.rst +4 -3
  20. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/pyproject.toml +2 -2
  21. maxapi_python-2.4.1/scripts/todo.py +48 -0
  22. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/__init__.py +4 -2
  23. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/_data/apk_fingerprints.json +102 -17
  24. maxapi_python-2.4.1/src/pymax/_data/rootca_ssl_rsa2022.crt +33 -0
  25. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/auth/service.py +14 -2
  26. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/chats/payloads.py +2 -1
  27. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/chats/service.py +7 -0
  28. maxapi_python-2.4.1/src/pymax/api/messages/__init__.py +1 -0
  29. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/messages/payloads.py +9 -3
  30. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/messages/service.py +106 -12
  31. maxapi_python-2.4.1/src/pymax/api/uploads/payloads.py +63 -0
  32. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/uploads/service.py +77 -62
  33. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/app.py +23 -4
  34. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/__init__.py +2 -0
  35. maxapi_python-2.4.1/src/pymax/auth/exceptions.py +9 -0
  36. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/providers.py +6 -2
  37. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/sms.py +11 -1
  38. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/base.py +83 -9
  39. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/client.py +39 -10
  40. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/client_web.py +15 -12
  41. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/config.py +63 -21
  42. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/base.py +58 -1
  43. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/video.py +32 -40
  44. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/voice.py +18 -4
  45. maxapi_python-2.4.1/src/pymax/fingerprint/fingerprint.py +30 -0
  46. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/fingerprint/models.py +1 -0
  47. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/chat.py +9 -5
  48. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/message.py +9 -3
  49. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/protocol.py +5 -1
  50. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/session/__init__.py +1 -1
  51. maxapi_python-2.4.1/src/pymax/session/models.py +41 -0
  52. maxapi_python-2.4.1/src/pymax/session/protocol.py +40 -0
  53. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/session/store.py +73 -5
  54. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/transport/tcp.py +11 -3
  55. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/call.py +7 -1
  56. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/contact.py +3 -3
  57. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/control.py +3 -0
  58. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/enums.py +16 -0
  59. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/video.py +3 -3
  60. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/enums.py +7 -0
  61. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/message.py +87 -7
  62. maxapi_python-2.4.1/src/pymax/versions/__init__.py +2 -0
  63. maxapi_python-2.4.1/src/pymax/versions/catalog.py +104 -0
  64. maxapi_python-2.4.1/src/pymax/versions/exceptions.py +10 -0
  65. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/api/test_auth_service.py +8 -19
  66. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/api/test_chat_user_self_session_services.py +10 -2
  67. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/api/test_message_service.py +6 -3
  68. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/api/test_upload_service.py +6 -7
  69. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/app/test_app_runtime.py +122 -1
  70. maxapi_python-2.4.1/tests/app/test_client_user_agent_config.py +37 -0
  71. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/auth/test_auth_flows.py +4 -1
  72. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/conftest.py +11 -2
  73. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/connection/test_readers_and_transports.py +1 -1
  74. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/domain/test_bound_models.py +1 -1
  75. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/session/test_store.py +65 -0
  76. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/uv.lock +5 -5
  77. maxapi_python-2.4.0/src/pymax/api/messages/__init__.py +0 -1
  78. maxapi_python-2.4.0/src/pymax/api/uploads/payloads.py +0 -31
  79. maxapi_python-2.4.0/src/pymax/fingerprint/fingerprint.py +0 -47
  80. maxapi_python-2.4.0/src/pymax/session/models.py +0 -11
  81. maxapi_python-2.4.0/src/pymax/session/protocol.py +0 -14
  82. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  83. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  84. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/ISSUE_TEMPLATE/refactor.md +0 -0
  85. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/pull_request_template.md +0 -0
  86. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/workflows/publish.yml +0 -0
  87. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.github/workflows/tests.yml +0 -0
  88. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.gitignore +0 -0
  89. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/.pre-commit-config.yaml +0 -0
  90. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/LICENSE +0 -0
  91. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/_static/.gitkeep +0 -0
  92. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/client-client.rst +0 -0
  93. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/client-config.rst +0 -0
  94. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/client-web.rst +0 -0
  95. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/files.rst +0 -0
  96. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/api/router.rst +0 -0
  97. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/conf.py +0 -0
  98. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/examples.rst +0 -0
  99. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/formatting.rst +0 -0
  100. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/getting-started.rst +0 -0
  101. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-1-0.rst +0 -0
  102. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-1-1.rst +0 -0
  103. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-1-2.rst +0 -0
  104. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-1-3.rst +0 -0
  105. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-2-0.rst +0 -0
  106. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-3-0.rst +0 -0
  107. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-3-1.rst +0 -0
  108. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/release-2-4-0.rst +0 -0
  109. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/router.rst +0 -0
  110. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/audio_attachment.rst +0 -0
  111. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/call_attachment.rst +0 -0
  112. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/chat.rst +0 -0
  113. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/contact_attachment.rst +0 -0
  114. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/contact_info.rst +0 -0
  115. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/control_attachment.rst +0 -0
  116. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/element.rst +0 -0
  117. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/file_attachment.rst +0 -0
  118. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/folder.rst +0 -0
  119. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/folder_list.rst +0 -0
  120. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/folder_update.rst +0 -0
  121. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/inline_keyboard_attachment.rst +0 -0
  122. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/message.rst +0 -0
  123. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/message_delete_event.rst +0 -0
  124. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/message_read_event.rst +0 -0
  125. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/name.rst +0 -0
  126. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/photo_attachment.rst +0 -0
  127. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/poll.rst +0 -0
  128. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/poll_attachment.rst +0 -0
  129. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/presence_event.rst +0 -0
  130. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/profile.rst +0 -0
  131. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/reaction_counter.rst +0 -0
  132. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/reaction_info.rst +0 -0
  133. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/reaction_update_event.rst +0 -0
  134. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/read_state.rst +0 -0
  135. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/session.rst +0 -0
  136. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/share_attachment.rst +0 -0
  137. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/sticker_attachment.rst +0 -0
  138. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/sync_overrides.rst +0 -0
  139. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/sync_state.rst +0 -0
  140. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/typing_event.rst +0 -0
  141. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/user.rst +0 -0
  142. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/types/video_attachment.rst +0 -0
  143. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/docs/users.rst +0 -0
  144. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/__init__.py +0 -0
  145. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/auth/__init__.py +0 -0
  146. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/auth/enums.py +0 -0
  147. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/auth/payloads.py +0 -0
  148. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/auth/types.py +0 -0
  149. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/binding.py +0 -0
  150. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/bots/__init__.py +0 -0
  151. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/bots/payloads.py +0 -0
  152. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/bots/service.py +0 -0
  153. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/chats/__init__.py +0 -0
  154. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/chats/enums.py +0 -0
  155. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/facade.py +0 -0
  156. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/messages/enums.py +0 -0
  157. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/models.py +0 -0
  158. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/response.py +0 -0
  159. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/self/__init__.py +0 -0
  160. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/self/enums.py +0 -0
  161. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/self/payloads.py +0 -0
  162. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/self/service.py +0 -0
  163. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/session/__init__.py +0 -0
  164. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/session/enums.py +0 -0
  165. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/session/payloads.py +0 -0
  166. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/session/service.py +0 -0
  167. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/uploads/__init__.py +0 -0
  168. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/uploads/models.py +0 -0
  169. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/users/__init__.py +0 -0
  170. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/users/enums.py +0 -0
  171. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/users/payloads.py +0 -0
  172. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/api/users/service.py +0 -0
  173. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/base.py +0 -0
  174. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/email.py +0 -0
  175. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/models.py +0 -0
  176. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/qr.py +0 -0
  177. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/auth/service.py +0 -0
  178. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/__init__.py +0 -0
  179. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/connection.py +0 -0
  180. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/pending.py +0 -0
  181. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/readers/__init__.py +0 -0
  182. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/readers/base.py +0 -0
  183. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/readers/tcp.py +0 -0
  184. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/connection/readers/ws.py +0 -0
  185. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/__init__.py +0 -0
  186. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/dispatcher.py +0 -0
  187. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/enums.py +0 -0
  188. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/mapping.py +0 -0
  189. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/resolvers.py +0 -0
  190. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/dispatch/router.py +0 -0
  191. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/exceptions.py +0 -0
  192. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/__init__.py +0 -0
  193. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/file.py +0 -0
  194. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/photo.py +0 -0
  195. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/files/static.py +0 -0
  196. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/fingerprint/__init__.py +0 -0
  197. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/formatting/__init__.py +0 -0
  198. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/formatting/markdown.py +0 -0
  199. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/__init__.py +0 -0
  200. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/auth.py +0 -0
  201. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/base.py +0 -0
  202. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/bots.py +0 -0
  203. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/self.py +0 -0
  204. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/infra/user.py +0 -0
  205. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/logging.py +0 -0
  206. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/__init__.py +0 -0
  207. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/base.py +0 -0
  208. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/enums.py +0 -0
  209. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/models.py +0 -0
  210. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/tcp/__init__.py +0 -0
  211. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/tcp/compression.py +0 -0
  212. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/tcp/framing.py +0 -0
  213. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/tcp/payload.py +0 -0
  214. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/tcp/protocol.py +0 -0
  215. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/ws/__init__.py +0 -0
  216. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/protocol/ws/protocol.py +0 -0
  217. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/py.typed +0 -0
  218. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/routers.py +0 -0
  219. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/telemetry/__init__.py +0 -0
  220. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/telemetry/navigation.py +0 -0
  221. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/telemetry/payloads.py +0 -0
  222. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/telemetry/service.py +0 -0
  223. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/transport/__init__.py +0 -0
  224. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/transport/base.py +0 -0
  225. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/transport/websocket.py +0 -0
  226. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/__init__.py +0 -0
  227. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/__init__.py +0 -0
  228. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/__init__.py +0 -0
  229. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/audio.py +0 -0
  230. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/file.py +0 -0
  231. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/keyboards/__init__.py +0 -0
  232. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/keyboards/inline.py +0 -0
  233. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/photo.py +0 -0
  234. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/poll.py +0 -0
  235. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/share.py +0 -0
  236. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/sticker.py +0 -0
  237. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/attachments/unknown.py +0 -0
  238. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/auth.py +0 -0
  239. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/base.py +0 -0
  240. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/bots.py +0 -0
  241. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/chat.py +0 -0
  242. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/element.py +0 -0
  243. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/error.py +0 -0
  244. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/folder.py +0 -0
  245. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/handshake.py +0 -0
  246. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/login.py +0 -0
  247. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/member.py +0 -0
  248. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/name.py +0 -0
  249. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/presence.py +0 -0
  250. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/profile.py +0 -0
  251. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/session.py +0 -0
  252. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/sync.py +0 -0
  253. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/domain/user.py +0 -0
  254. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/__init__.py +0 -0
  255. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/file.py +0 -0
  256. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/mark.py +0 -0
  257. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/message.py +0 -0
  258. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/presence.py +0 -0
  259. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/reaction.py +0 -0
  260. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/typing.py +0 -0
  261. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/video.py +0 -0
  262. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/src/pymax/types/events/voice.py +0 -0
  263. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/__init__.py +0 -0
  264. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/connection/test_connection.py +0 -0
  265. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/dispatch/test_dispatcher.py +0 -0
  266. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/domain/test_login_models.py +0 -0
  267. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/domain/test_message_models.py +0 -0
  268. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/domain/test_user_models.py +0 -0
  269. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/files/test_files_and_formatting.py +0 -0
  270. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/protocol/test_protocols.py +0 -0
  271. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/telemetry/test_telemetry.py +0 -0
  272. {maxapi_python-2.4.0 → maxapi_python-2.4.1}/tests/test_logging.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: maxapi-python
3
- Version: 2.4.0
3
+ Version: 2.4.1
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
@@ -43,6 +43,7 @@ Python-библиотека для Max API.
43
43
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
44
44
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
45
45
  [![Package](https://img.shields.io/badge/package-maxapi--python-orange.svg)](https://pypi.org/project/maxapi-python/)
46
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/maxapi-python?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/maxapi-python)
46
47
 
47
48
  > [!WARNING]
48
49
  > PyMax использует неофициальный внутренний API Max. API может измениться без
@@ -62,10 +63,11 @@ WebSocket.
62
63
  - Авторизация по телефону и SMS-коду через `Client`.
63
64
  - QR-авторизация web-клиента через `WebClient`.
64
65
  - Роутеры, фильтры, `on_start`, raw-события и typed events.
65
- - Сообщения: отправка, ответы, reply, реакции, pin, read, delete и история.
66
+ - Сообщения: отправка и планирование, ответы, реакции, pin, read, delete и история.
66
67
  - Чаты, группы, участники, invite-ссылки и настройки групп.
67
68
  - Пользователи, контакты, профиль, папки, активные сессии и 2FA.
68
- - Вложения: `Photo`, `File`, `Video`.
69
+ - Вложения: `Photo`, `File`, `Video`, `Voice`, `VideoNote`.
70
+ - Выбор версии mobile-клиента с локальным или обновляемым каталогом fingerprints.
69
71
  - SQLite-сессии, sync-state, reconnect и debug-логи.
70
72
  - Pydantic-модели и удобные domain-объекты.
71
73
 
@@ -5,6 +5,7 @@ Python-библиотека для Max API.
5
5
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
6
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![Package](https://img.shields.io/badge/package-maxapi--python-orange.svg)](https://pypi.org/project/maxapi-python/)
8
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/maxapi-python?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/maxapi-python)
8
9
 
9
10
  > [!WARNING]
10
11
  > PyMax использует неофициальный внутренний API Max. API может измениться без
@@ -24,10 +25,11 @@ WebSocket.
24
25
  - Авторизация по телефону и SMS-коду через `Client`.
25
26
  - QR-авторизация web-клиента через `WebClient`.
26
27
  - Роутеры, фильтры, `on_start`, raw-события и typed events.
27
- - Сообщения: отправка, ответы, reply, реакции, pin, read, delete и история.
28
+ - Сообщения: отправка и планирование, ответы, реакции, pin, read, delete и история.
28
29
  - Чаты, группы, участники, invite-ссылки и настройки групп.
29
30
  - Пользователи, контакты, профиль, папки, активные сессии и 2FA.
30
- - Вложения: `Photo`, `File`, `Video`.
31
+ - Вложения: `Photo`, `File`, `Video`, `Voice`, `VideoNote`.
32
+ - Выбор версии mobile-клиента с локальным или обновляемым каталогом fingerprints.
31
33
  - SQLite-сессии, sync-state, reconnect и debug-логи.
32
34
  - Pydantic-модели и удобные domain-объекты.
33
35
 
@@ -0,0 +1,44 @@
1
+ # PyMax TODO :3
2
+
3
+ > [!NOTE]
4
+ > This file is maintained by the project owner. Please do not edit it in pull requests.
5
+
6
+ Format:
7
+ - Refactoring / Bugs: `TEXT. PATH. PRIORITY`
8
+ - Features: `TEXT. TARGET. PRIORITY`
9
+
10
+ ## Refactoring
11
+
12
+ - [ ] Перевести все аргументы, связанные со временем, на `DateTimeUnion`. `api/messages/service.py:65`. P: 50
13
+ - [ ] Перенести часть общих типов в `common`, например `SendAttachments`. -. P: 40
14
+ - [ ] Пересмотреть систему типов, возможно разбить её на более мелкие части. -. P: 70
15
+
16
+ ## Bugs
17
+
18
+ - [X] Исправить голосовые/кружки. `api/upload/service.py`. P: 100
19
+ - [X] Исправить генерацию device_id. `src/pymax/base.py:111`. P: 80
20
+
21
+ ## Features
22
+
23
+ - [ ] FSM. Почти готово. `2.5.0`. P: 80
24
+ - [ ] DI. `2.5.0`. P: 75
25
+ - [ ] Улучшенная система фильтров. Почти готово. `2.5.0`. P: 90
26
+
27
+
28
+ # Autogenerated TODO. Please, dont touch it
29
+ - [ ] src/pymax/api/chats/payloads.py:100: ENUMM!!!
30
+ - [ ] src/pymax/api/chats/payloads.py:123: ENUMM!!!
31
+ - [ ] src/pymax/api/messages/payloads.py:32: enum?
32
+ - [ ] src/pymax/api/messages/service.py:94: TypeAlias
33
+ - [ ] src/pymax/api/uploads/service.py:68: ENUM!!!!
34
+ - [ ] src/pymax/api/uploads/service.py:286: Error handing (yes, with 200 status 💔)
35
+ - [ ] src/pymax/api/users/service.py:133: maybe also return phone mapping?
36
+ - [ ] src/pymax/base.py:226: maybe impl it better way
37
+ - [ ] src/pymax/config.py:52: delete maybe
38
+ - [ ] src/pymax/dispatch/dispatcher.py:190: create iter_on_start_handlers
39
+ - [ ] src/pymax/protocol/tcp/payload.py:34: deprecate? idk
40
+ - [ ] src/pymax/transport/websocket.py:28: origin should be configurable
41
+ - [ ] src/pymax/types/domain/attachments/video.py:70: idk maybe | None = None better
42
+ - [ ] src/pymax/types/domain/user.py:14: move to another file
43
+ - [ ] src/pymax/types/events/message.py:49: impl it in the better way maybe
44
+ - [ ] src/pymax/versions/catalog.py:56: msg
@@ -129,9 +129,8 @@ login или ping:
129
129
  -------------
130
130
 
131
131
  ``client.me`` равен ``None``
132
- Login еще не завершился или клиент не запущен. Читайте профиль внутри
133
- ``on_start`` или после успешного ``await client.start()`` в собственном
134
- lifecycle.
132
+ Login еще не завершился. Читайте профиль внутри ``on_start`` или после
133
+ успешного ``await client.connect()``.
135
134
 
136
135
  Фото профиля не обновилось
137
136
  Если переданы и ``photo``, и ``photo_token``, PyMax загрузит ``photo`` и
@@ -33,3 +33,5 @@ Auth API
33
33
 
34
34
  .. autoclass:: pymax.ConsoleQrHandler
35
35
  :members:
36
+
37
+ .. autoclass:: pymax.PasswordAttemptsExceededError
@@ -0,0 +1,20 @@
1
+ Session storage
2
+ ===============
3
+
4
+ .. currentmodule:: pymax.session
5
+
6
+ ``Client`` и ``WebClient`` используют этот контракт для token,
7
+ device/user-agent и sync-state. Выбор и lifecycle хранилища описаны в разделе
8
+ :ref:`client-session-guide`.
9
+
10
+ .. autoclass:: SessionInfo
11
+ :members:
12
+
13
+ .. autoclass:: StoreProtocol
14
+ :members:
15
+
16
+ .. autoclass:: SessionStore
17
+ :members:
18
+
19
+ .. autoclass:: InMemoryStore
20
+ :members:
@@ -0,0 +1,12 @@
1
+ Version Catalog
2
+ ===============
3
+
4
+ .. currentmodule:: pymax.versions
5
+
6
+ ``VersionCatalog`` связывает версию Android-клиента с build number и
7
+ fingerprint, которые использует ``Client``.
8
+
9
+ .. autoclass:: VersionCatalog
10
+ :members:
11
+
12
+ .. autoclass:: VersionNotFoundError
@@ -23,3 +23,5 @@ Clients API
23
23
  client-client
24
24
  client-web
25
25
  client-config
26
+ client-session
27
+ client-versions
@@ -88,6 +88,30 @@ Provider нужен, когда код приходит не из консоли
88
88
  Если provider вернет пустую строку или Max отклонит пароль, ``SmsAuthFlow``
89
89
  попросит пароль снова.
90
90
 
91
+ Количество попыток можно ограничить через ``ExtraConfig``:
92
+
93
+ .. code-block:: python
94
+
95
+ from pymax import Client, ExtraConfig, PasswordAttemptsExceededError
96
+
97
+ client = Client(
98
+ phone="+79990000000",
99
+ password_provider=EnvPasswordProvider(),
100
+ extra_config=ExtraConfig(password_max_attempts=3),
101
+ )
102
+
103
+ try:
104
+ await client.connect()
105
+ except PasswordAttemptsExceededError:
106
+ print("Пароль 2FA не принят")
107
+
108
+ ``password_max_attempts=None`` означает неограниченное число попыток и
109
+ сохраняет прежнее поведение. Пустой пароль, ``ApiError``, ошибка в ответе Max
110
+ и ответ без login token расходуют одну попытку. При ``0`` или отрицательном
111
+ значении provider не вызывается, а ``PasswordAttemptsExceededError``
112
+ возникает сразу. Исключение наследуется напрямую от ``Exception``, поэтому
113
+ его нужно перехватывать отдельно от ``PyMaxError``.
114
+
91
115
  Кастомный QR handler
92
116
  --------------------
93
117
 
@@ -129,10 +129,13 @@ login/sync, а также методы для загрузки, создания
129
129
 
130
130
  .. code-block:: python
131
131
 
132
+ from pymax import Photo
133
+
132
134
  await client.change_group_profile(
133
135
  chat_id=123456,
134
136
  name="Новый заголовок",
135
137
  description="Описание группы",
138
+ photo=Photo(path="group.jpg"),
136
139
  )
137
140
 
138
141
  await client.change_group_settings(
@@ -141,6 +144,11 @@ login/sync, а также методы для загрузки, создания
141
144
  only_admin_can_call=True,
142
145
  )
143
146
 
147
+ ``name``, ``description`` и ``photo`` независимы: передавайте только поля,
148
+ которые нужно изменить. Значение ``None`` исключает поле из запроса. Перед
149
+ обновлением профиля PyMax автоматически загружает ``Photo`` и отправляет Max
150
+ полученный photo token.
151
+
144
152
  Через объект ``Chat`` можно менять настройки и перевыпускать invite-ссылку:
145
153
 
146
154
  .. code-block:: python
@@ -7,9 +7,9 @@ Client
7
7
  ``Client`` и ``WebClient`` - главные объекты библиотеки. Они держат соединение,
8
8
  авторизацию, локальную сессию, кеш профиля/чатов и методы для API Max.
9
9
 
10
- ``Client`` не является обычным HTTP-wrapper-ом на один запрос. После
11
- ``await client.start()`` он остается подключенным, слушает события Max,
12
- отвечает на ping и вызывает ваши handler-ы.
10
+ ``Client`` не является обычным HTTP-wrapper-ом на один запрос. После запуска
11
+ он остается подключенным, слушает события Max, отвечает на ping и вызывает
12
+ ваши handler-ы.
13
13
 
14
14
  Как выбрать клиента
15
15
  -------------------
@@ -27,12 +27,31 @@ Client
27
27
 
28
28
  1. Вы создаете ``Client`` или ``WebClient``.
29
29
  2. Регистрируете handler-ы и подключаете роутеры.
30
- 3. Вызываете ``await client.start()``.
30
+ 3. Вызываете ``await client.start()`` или ``await client.connect()``.
31
31
  4. PyMax открывает соединение, делает handshake и login.
32
32
  5. После login доступны ``client.me`` и ``client.chats``.
33
33
  6. Вызывается ``on_start``.
34
34
  7. Клиент слушает события до закрытия соединения или отмены задачи.
35
35
 
36
+ ``start()`` - long-running режим с автоматическим reconnect. Метод не
37
+ возвращается, пока соединение не закрыто штатно или задача не отменена.
38
+
39
+ ``connect()`` выполняет один цикл подключения, login и ``on_start``, после
40
+ чего возвращается, оставляя соединение открытым. Он не запускает reconnect
41
+ loop: приложение само выполняет работу и затем вызывает ``stop()`` или
42
+ ``close()``.
43
+
44
+ .. code-block:: python
45
+
46
+ await client.connect()
47
+ try:
48
+ await client.send_message(chat_id=123456, text="Готово")
49
+ finally:
50
+ await client.close()
51
+
52
+ После успешного запуска состояние соединения доступно через
53
+ ``client.is_connected``.
54
+
36
55
  Если ``start()`` запущен отдельной задачей, ``stop()`` штатно закрывает
37
56
  соединение и завершает эту задачу без ``CancelledError``:
38
57
 
@@ -51,7 +70,7 @@ Client
51
70
  После успешного login клиент хранит несколько кешей, которые пришли от Max:
52
71
 
53
72
  ``client.me``
54
- Профиль текущего аккаунта или ``None``, если login еще не завершился.
73
+ Профиль текущего аккаунта.
55
74
 
56
75
  ``client.chats``
57
76
  Чаты из login/sync. Это не гарантированно полный список всех чатов.
@@ -106,7 +125,46 @@ Client
106
125
  Имя файла сессии внутри ``work_dir``.
107
126
 
108
127
  ``extra_config``
109
- Настройки соединения, логов, reconnect, token, device/user-agent и sync.
128
+ Настройки соединения, логов, reconnect, token, хранения сессии,
129
+ device/user-agent и sync.
130
+
131
+ ``app_version``
132
+ Версия Android-клиента, которую ``Client`` использует для user-agent и
133
+ fingerprint. По умолчанию - версия, возвращаемая
134
+ ``VersionCatalog.recommended()``.
135
+
136
+ ``catalog``
137
+ Каталог fingerprints для ``app_version``. По умолчанию используется
138
+ встроенный каталог.
139
+
140
+ Версия mobile-клиента
141
+ ---------------------
142
+
143
+ ``Client`` связывает выбранную ``app_version`` с соответствующими build number
144
+ и fingerprint. Разрешение версии происходит при ``connect()`` или ``start()``,
145
+ а не при создании объекта клиента.
146
+
147
+ .. code-block:: python
148
+
149
+ from pymax import Client
150
+ from pymax.versions import VersionCatalog
151
+
152
+ client = Client(
153
+ phone="+79990000000",
154
+ app_version="26.28.0",
155
+ catalog=VersionCatalog(remote=True),
156
+ )
157
+
158
+ Обычный ``VersionCatalog()`` использует только данные, поставляемые вместе с
159
+ PyMax. При ``remote=True`` метод ``load()`` загружает свежий каталог с
160
+ ``hashes.pymax.org`` и добавляет его записи поверх встроенных. Сетевые,
161
+ HTTP- и validation-ошибки удаленного каталога не скрываются и возникают во
162
+ время ``connect()``/``start()``.
163
+
164
+ Если выбранной версии нет в итоговом каталоге, PyMax выбрасывает
165
+ ``VersionNotFoundError``. Пользовательский ``ExtraConfig.user_agent`` не
166
+ отменяет проверку ``app_version``: fingerprint для версии всё равно должен
167
+ существовать.
110
168
 
111
169
  Тип устройства
112
170
  ---------------
@@ -209,6 +267,8 @@ Client
209
267
  qr_provider=ConfirmQrWithClient(mobile_client),
210
268
  )
211
269
 
270
+ .. _client-session-guide:
271
+
212
272
  Сессия и sync-state
213
273
  -------------------
214
274
 
@@ -218,6 +278,7 @@ Client
218
278
  * ``device_id``;
219
279
  * телефон;
220
280
  * ``mt_instance_id``;
281
+ * device/user-agent;
221
282
  * sync-маркеры ``chats_sync``, ``contacts_sync``, ``drafts_sync``,
222
283
  ``presence_sync`` и ``config_hash``.
223
284
 
@@ -225,11 +286,49 @@ Client
225
286
  ``session_name="account.db"`` это будет ``cache/account.db``. Если файл удалить,
226
287
  PyMax потеряет token и попросит авторизацию снова.
227
288
 
289
+ Для автоматически создаваемого user-agent PyMax восстанавливает из сессии
290
+ модель устройства, версию ОС, экран, locale и timezone. ``app_version`` и build
291
+ number всегда берутся из конфигурации текущего запуска, поэтому смена версии
292
+ клиента не сбрасывает сохраненный профиль устройства. Явный
293
+ ``ExtraConfig.user_agent`` имеет приоритет и заменяет значение из сессии.
294
+
295
+ Старый SQLite-файл обновляется автоматически: PyMax добавляет nullable-колонку
296
+ ``user_agent`` и при первом успешном login сохраняет в нее текущий payload.
297
+
228
298
  При login PyMax отправляет сохраненные маркеры серверу. Если маркер актуален,
229
299
  сервер может вернуть только изменения. Поэтому повторный запуск отличается от
230
300
  первого: первый запуск обычно использует ``-1`` и получает начальный sync,
231
301
  а последующие запуски продолжают с сохраненного состояния.
232
302
 
303
+ Пользовательский ``StoreProtocol`` может возвращать
304
+ ``SessionInfo.user_agent=None`` для совместимости, но тогда профиль устройства
305
+ не сохраняется между запусками. Чтобы получить стандартное поведение, храните и
306
+ возвращайте это необязательное поле вместе с остальными данными сессии.
307
+
308
+ Сессия только в памяти
309
+ ----------------------
310
+
311
+ Чтобы не создавать и не обновлять SQLite-файл, передайте
312
+ ``persist_session=False``:
313
+
314
+ .. code-block:: python
315
+
316
+ from pymax import Client, ExtraConfig
317
+
318
+ client = Client(
319
+ phone="+79990000000",
320
+ extra_config=ExtraConfig(
321
+ persist_session=False,
322
+ reconnect=False,
323
+ ),
324
+ )
325
+
326
+ В этом режиме PyMax использует отдельный ``InMemoryStore``. Переданный
327
+ ``ExtraConfig.store`` игнорируется. Сессия доступна только текущему runtime и
328
+ теряется при его пересоздании; reconnect без ``ExtraConfig.token`` поэтому снова
329
+ запускает SMS- или QR-авторизацию. Если автоматический reconnect в таком режиме
330
+ не нужен, отключите его как в примере.
331
+
233
332
  Принудительный sync
234
333
  -------------------
235
334
 
@@ -278,6 +377,10 @@ Reconnect
278
377
  а новый ``App`` снова получает тот же root router. ``on_start`` вызывается
279
378
  после каждого успешного reconnect.
280
379
 
380
+ Если сервер отозвал login token, ``ExtraConfig(relogin=True)`` по умолчанию
381
+ сбрасывает текущую сессию и запускает авторизацию заново. Значение ``False``
382
+ отключает этот автоматический сброс.
383
+
281
384
  Перед повторным подключением можно зарегистрировать ``on_disconnect``:
282
385
 
283
386
  .. code-block:: python
@@ -93,6 +93,8 @@ Max не всегда присылает полный объект сообще
93
93
  Что делать при Pydantic validation error?
94
94
  -----------------------------------------
95
95
 
96
- Max мог прислать новый или неполный формат payload. Включите ``DEBUG``, снимите
97
- raw payload через ``on_raw`` и обновите PyMax. Если ошибка повторяется, заведите
98
- issue с очищенным payload без token, телефонов и приватных URL.
96
+ Неизвестный тип вложения сохраняется как ``UnknownAttachment`` и сам по себе не
97
+ должен ломать сообщение. Validation error обычно означает неполный или
98
+ измененный payload уже известной модели. Включите ``DEBUG``, снимите raw payload
99
+ через ``on_raw`` и обновите PyMax. Если ошибка повторяется, заведите issue с
100
+ очищенным payload без token, телефонов и приватных URL.
@@ -17,7 +17,8 @@ Files
17
17
 
18
18
  ``Voice``
19
19
  Голосовое сообщение. Поддерживается только формат OGG; PyMax не
20
- конвертирует другие аудиоформаты.
20
+ конвертирует другие аудиоформаты. Длительность можно передать вручную или
21
+ определить автоматически через extra ``video``.
21
22
 
22
23
  ``VideoNote``
23
24
  Круглое видеосообщение. Можно передать длительность вручную или установить
@@ -79,8 +80,9 @@ Files
79
80
  ``Voice`` и ``VideoNote`` имя берется из ``path`` или ``url``, если не
80
81
  передано явно.
81
82
 
82
- Если длительность ``VideoNote`` не передана, установите дополнительную
83
- зависимость:
83
+ ``duration`` для ``Voice`` и ``VideoNote`` задается в миллисекундах. Если
84
+ длительность не передана, установите дополнительную зависимость для её
85
+ автоматического определения:
84
86
 
85
87
  .. code-block:: console
86
88
 
@@ -121,11 +123,20 @@ orientation hint. H.264 profile и level специально фиксирова
121
123
  1. PyMax запрашивает у Max временный upload URL.
122
124
  2. Читает файл из ``path``, ``url`` или ``raw``.
123
125
  3. Загружает данные HTTP-запросом.
124
- 4. Для ``File``, ``Video``, ``Voice`` и ``VideoNote`` ждет служебное событие
125
- готовности до 60 секунд.
126
+ 4. Для ``File`` и обычного ``Video`` ждет служебное событие готовности до
127
+ 60 секунд.
126
128
  5. Подставляет token/file_id/video_id в отправляемое сообщение.
127
129
 
128
130
  Фото проходит проще: после HTTP-upload PyMax сразу достает token из ответа.
131
+ ``Voice`` и ``VideoNote`` отправляются сразу после HTTP-upload. Если Max
132
+ ответил ``attachment.not.ready``, PyMax ждет событие готовности до 60 секунд и
133
+ повторяет отправку сообщения один раз.
134
+
135
+ Общий timeout HTTP-загрузки ``File``, ``Video``, ``Voice`` и ``VideoNote``
136
+ задается через ``ExtraConfig(upload_timeout=...)`` в секундах; значение по
137
+ умолчанию - ``900``. Он не применяется к ``Photo`` и не меняет отдельный
138
+ 60-секундный лимит ожидания обработки. ``0`` и отрицательные значения
139
+ отключают общий timeout, но не отдельный 60-секундный socket/read timeout.
129
140
 
130
141
  Скачать входящий файл
131
142
  ---------------------
@@ -170,5 +181,5 @@ orientation hint. H.264 profile и level специально фиксирова
170
181
  что событие готовности файла не пришло за 60 секунд.
171
182
 
172
183
  ``Automatic video duration detection requires the 'video' extra``
173
- Передайте ``duration`` в миллисекундах или установите
174
- ``maxapi-python[video]``.
184
+ Для ``Voice`` или ``VideoNote`` передайте ``duration`` в миллисекундах либо
185
+ установите ``maxapi-python[video]``.
@@ -22,6 +22,7 @@ PyMax - асинхронная Python-библиотека для Max API. Он
22
22
  :maxdepth: 1
23
23
  :caption: Новости
24
24
 
25
+ release-2-4-1
25
26
  release-2-4-0
26
27
  release-2-3-1
27
28
  release-2-3-0
@@ -83,6 +83,57 @@ Messages
83
83
  source_chat_id=123456,
84
84
  )
85
85
 
86
+ Reply и forward во входящем сообщении
87
+ -------------------------------------
88
+
89
+ Если сообщение является reply или forward, поле ``message.link`` содержит
90
+ исходное ``message`` и его ``chat_id``. Для forward Max также может прислать
91
+ ``chat_name``, ``chat_link``, ``chat_access_type`` и ``chat_icon_url``; для
92
+ скрытого источника эти поля равны ``None``. У обычного сообщения ``link`` равен
93
+ ``None``.
94
+
95
+ .. code-block:: python
96
+
97
+ @client.on_message()
98
+ async def on_message(message: Message, client: Client) -> None:
99
+ if message.link is not None:
100
+ print("source:", message.link.chat_id, message.link.message.id)
101
+
102
+ Отложенная отправка
103
+ -------------------
104
+
105
+ ``client.send_message()``, ``message.answer()`` и ``message.reply()`` принимают
106
+ ``send_at`` трех видов:
107
+
108
+ * ``datetime`` - абсолютное время отправки;
109
+ * ``timedelta`` - задержка относительно текущего локального времени;
110
+ * ``int`` - Unix time в секундах.
111
+
112
+ .. code-block:: python
113
+
114
+ from datetime import datetime, timedelta, timezone
115
+
116
+ await client.send_message(
117
+ chat_id=123456,
118
+ text="Через пять минут",
119
+ send_at=timedelta(minutes=5),
120
+ )
121
+
122
+ await client.send_message(
123
+ chat_id=123456,
124
+ text="В назначенное время",
125
+ send_at=datetime(2026, 9, 1, 12, 0, tzinfo=timezone.utc),
126
+ notify=False,
127
+ )
128
+
129
+ ``None`` и ``0`` означают немедленную отправку. Значение ``notify`` также
130
+ используется сервером при срабатывании отложенного сообщения.
131
+
132
+ У полученного отложенного сообщения поле ``delayed_attributes`` содержит
133
+ ``time_to_fire`` в миллисекундах и флаги уведомлений. Для обычного сообщения
134
+ оно равно ``None``. Получить отложенные сообщения можно через
135
+ ``fetch_history(item_type=ItemType.DELAYED)``.
136
+
86
137
  Опросы
87
138
  ------
88
139
 
@@ -135,7 +186,7 @@ Messages
135
186
  print(state.total)
136
187
 
137
188
  Ответ, реакции, удаление и прочтение
138
- ----------------------------------------
189
+ ------------------------------------
139
190
 
140
191
  .. code-block:: python
141
192
 
@@ -160,6 +211,11 @@ Messages
160
211
  WebSocket-клиент - как ``str``. Если вызываете метод напрямую, выбирайте
161
212
  тип по клиенту.
162
213
 
214
+ Методы ``add_reaction()``, ``get_reactions()`` и ``remove_reaction()``
215
+ принимают ID сообщений только как ``int``. При этом ``get_reactions()``
216
+ возвращает словарь со строковыми ключами, потому что именно так ID приходят в
217
+ ответе Max.
218
+
163
219
  Служебные события
164
220
  -----------------
165
221
 
@@ -232,10 +288,15 @@ Max присылает разные формы событий. Некоторы
232
288
  полю ``type``: фото, видео, файл, стикер, аудио, опрос, контакт, звонок, share
233
289
  или inline-клавиатура.
234
290
 
291
+ Неизвестный ``_type`` не отклоняет все сообщение: PyMax возвращает
292
+ ``UnknownAttachment``, сохраняет исходный тип в ``type``, а остальные поля - в
293
+ ``model_extra``. Это позволяет принять payload нового типа до добавления его
294
+ отдельной модели в библиотеку.
295
+
235
296
  .. code-block:: python
236
297
 
237
298
  from pymax import Client, Message
238
- from pymax.types.domain import FileAttachment, PhotoAttachment
299
+ from pymax.types.domain import FileAttachment, PhotoAttachment, UnknownAttachment
239
300
 
240
301
  @client.on_message()
241
302
  async def on_message(message: Message, client: Client) -> None:
@@ -252,6 +313,8 @@ Max присылает разные формы событий. Некоторы
252
313
  file_id=attach.file_id,
253
314
  )
254
315
  print(file_info.url if file_info else "no url")
316
+ elif isinstance(attach, UnknownAttachment):
317
+ print("unknown:", attach.type, attach.model_extra)
255
318
 
256
319
  Частые ошибки
257
320
  -------------
@@ -266,6 +329,7 @@ Max присылает разные формы событий. Некоторы
266
329
  знаете ``chat_id`` из другого источника.
267
330
 
268
331
  Pydantic validation error на attachments
269
- Max мог прислать новый или неполный тип вложения. Включите debug-логи,
270
- посмотрите raw payload через ``on_raw`` и обновите PyMax или добавьте
271
- обработку нового формата.
332
+ Неизвестный ``_type`` обрабатывается через ``UnknownAttachment``, но
333
+ поврежденный или неполный payload уже известного типа все еще может не пройти
334
+ валидацию. Включите debug-логи, посмотрите raw payload через ``on_raw`` и
335
+ обновите PyMax или добавьте обработку нового формата.