maxapi-python 2.1.0__tar.gz → 2.1.2__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 (223) hide show
  1. maxapi_python-2.1.2/.github/workflows/publish.yml +64 -0
  2. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/PKG-INFO +1 -1
  3. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/account.rst +15 -10
  4. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/index.rst +2 -0
  5. maxapi_python-2.1.2/docs/release-2-1-1.rst +16 -0
  6. maxapi_python-2.1.2/docs/release-2-1-2.rst +32 -0
  7. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/pyproject.toml +1 -1
  8. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/__init__.py +1 -1
  9. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/bots/payloads.py +1 -1
  10. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/bots/service.py +3 -7
  11. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/self/service.py +11 -4
  12. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/uploads/service.py +4 -2
  13. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/app.py +13 -16
  14. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/self.py +2 -6
  15. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/transport/tcp.py +4 -2
  16. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/folder.py +0 -6
  17. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/login.py +7 -19
  18. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/api/test_chat_user_self_session_services.py +1 -1
  19. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/app/test_app_runtime.py +18 -0
  20. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/connection/test_readers_and_transports.py +47 -0
  21. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/uv.lock +1 -1
  22. maxapi_python-2.1.0/.github/workflows/publish.yml +0 -84
  23. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  24. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  25. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.github/ISSUE_TEMPLATE/refactor.md +0 -0
  26. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.github/pull_request_template.md +0 -0
  27. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.gitignore +0 -0
  28. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/.pre-commit-config.yaml +0 -0
  29. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/LICENSE +0 -0
  30. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/README.md +0 -0
  31. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/_static/.gitkeep +0 -0
  32. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/api/auth.rst +0 -0
  33. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/api/client.rst +0 -0
  34. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/api/files.rst +0 -0
  35. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/api/router.rst +0 -0
  36. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/auth.rst +0 -0
  37. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/chats.rst +0 -0
  38. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/client.rst +0 -0
  39. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/conf.py +0 -0
  40. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/examples.rst +0 -0
  41. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/faq.rst +0 -0
  42. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/files.rst +0 -0
  43. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/formatting.rst +0 -0
  44. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/getting-started.rst +0 -0
  45. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/messages.rst +0 -0
  46. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/release-2-1-0.rst +0 -0
  47. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/router.rst +0 -0
  48. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/troubleshooting.rst +0 -0
  49. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/audio_attachment.rst +0 -0
  50. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/call_attachment.rst +0 -0
  51. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/chat.rst +0 -0
  52. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/contact_attachment.rst +0 -0
  53. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/control_attachment.rst +0 -0
  54. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/element.rst +0 -0
  55. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/enums.rst +0 -0
  56. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/file_attachment.rst +0 -0
  57. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/folder.rst +0 -0
  58. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/folder_list.rst +0 -0
  59. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/folder_update.rst +0 -0
  60. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/index.rst +0 -0
  61. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/inline_keyboard_attachment.rst +0 -0
  62. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/message.rst +0 -0
  63. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/message_delete_event.rst +0 -0
  64. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/name.rst +0 -0
  65. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/photo_attachment.rst +0 -0
  66. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/profile.rst +0 -0
  67. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/reaction_counter.rst +0 -0
  68. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/reaction_info.rst +0 -0
  69. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/read_state.rst +0 -0
  70. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/session.rst +0 -0
  71. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/share_attachment.rst +0 -0
  72. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/sticker_attachment.rst +0 -0
  73. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/sync_overrides.rst +0 -0
  74. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/sync_state.rst +0 -0
  75. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/user.rst +0 -0
  76. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/types/video_attachment.rst +0 -0
  77. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/docs/users.rst +0 -0
  78. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/__init__.py +0 -0
  79. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/auth/__init__.py +0 -0
  80. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/auth/enums.py +0 -0
  81. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/auth/payloads.py +0 -0
  82. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/auth/service.py +0 -0
  83. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/auth/types.py +0 -0
  84. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/bots/__init__.py +0 -0
  85. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/chats/__init__.py +0 -0
  86. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/chats/enums.py +0 -0
  87. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/chats/payloads.py +0 -0
  88. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/chats/service.py +0 -0
  89. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/facade.py +0 -0
  90. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/messages/__init__.py +0 -0
  91. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/messages/enums.py +0 -0
  92. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/messages/payloads.py +0 -0
  93. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/messages/service.py +0 -0
  94. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/models.py +0 -0
  95. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/response.py +0 -0
  96. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/self/__init__.py +0 -0
  97. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/self/enums.py +0 -0
  98. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/self/payloads.py +0 -0
  99. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/session/__init__.py +0 -0
  100. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/session/enums.py +0 -0
  101. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/session/payloads.py +0 -0
  102. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/session/service.py +0 -0
  103. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/uploads/__init__.py +0 -0
  104. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/uploads/models.py +0 -0
  105. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/uploads/payloads.py +0 -0
  106. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/users/__init__.py +0 -0
  107. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/users/enums.py +0 -0
  108. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/users/payloads.py +0 -0
  109. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/api/users/service.py +0 -0
  110. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/__init__.py +0 -0
  111. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/base.py +0 -0
  112. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/email.py +0 -0
  113. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/models.py +0 -0
  114. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/providers.py +0 -0
  115. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/qr.py +0 -0
  116. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/service.py +0 -0
  117. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/auth/sms.py +0 -0
  118. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/base.py +0 -0
  119. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/client.py +0 -0
  120. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/client_web.py +0 -0
  121. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/config.py +0 -0
  122. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/__init__.py +0 -0
  123. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/connection.py +0 -0
  124. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/pending.py +0 -0
  125. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/readers/__init__.py +0 -0
  126. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/readers/base.py +0 -0
  127. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/readers/tcp.py +0 -0
  128. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/connection/readers/ws.py +0 -0
  129. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/__init__.py +0 -0
  130. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/dispatcher.py +0 -0
  131. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/enums.py +0 -0
  132. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/mapping.py +0 -0
  133. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/resolvers.py +0 -0
  134. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/dispatch/router.py +0 -0
  135. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/exceptions.py +0 -0
  136. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/__init__.py +0 -0
  137. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/base.py +0 -0
  138. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/file.py +0 -0
  139. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/photo.py +0 -0
  140. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/static.py +0 -0
  141. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/files/video.py +0 -0
  142. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/formatting/__init__.py +0 -0
  143. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/formatting/markdown.py +0 -0
  144. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/__init__.py +0 -0
  145. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/auth.py +0 -0
  146. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/base.py +0 -0
  147. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/bots.py +0 -0
  148. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/chat.py +0 -0
  149. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/message.py +0 -0
  150. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/protocol.py +0 -0
  151. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/infra/user.py +0 -0
  152. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/logging.py +0 -0
  153. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/__init__.py +0 -0
  154. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/base.py +0 -0
  155. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/enums.py +0 -0
  156. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/models.py +0 -0
  157. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/tcp/__init__.py +0 -0
  158. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/tcp/compression.py +0 -0
  159. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/tcp/framing.py +0 -0
  160. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/tcp/payload.py +0 -0
  161. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/tcp/protocol.py +0 -0
  162. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/ws/__init__.py +0 -0
  163. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/protocol/ws/protocol.py +0 -0
  164. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/py.typed +0 -0
  165. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/routers.py +0 -0
  166. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/session/__init__.py +0 -0
  167. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/session/models.py +0 -0
  168. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/session/protocol.py +0 -0
  169. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/session/store.py +0 -0
  170. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/telemetry/__init__.py +0 -0
  171. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/telemetry/navigation.py +0 -0
  172. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/telemetry/payloads.py +0 -0
  173. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/telemetry/service.py +0 -0
  174. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/transport/__init__.py +0 -0
  175. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/transport/base.py +0 -0
  176. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/transport/websocket.py +0 -0
  177. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/__init__.py +0 -0
  178. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/__init__.py +0 -0
  179. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/__init__.py +0 -0
  180. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/audio.py +0 -0
  181. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/call.py +0 -0
  182. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/contact.py +0 -0
  183. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/control.py +0 -0
  184. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/enums.py +0 -0
  185. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/file.py +0 -0
  186. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/keyboards/__init__.py +0 -0
  187. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/keyboards/inline.py +0 -0
  188. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/photo.py +0 -0
  189. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/share.py +0 -0
  190. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/sticker.py +0 -0
  191. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/attachments/video.py +0 -0
  192. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/auth.py +0 -0
  193. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/base.py +0 -0
  194. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/bots.py +0 -0
  195. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/chat.py +0 -0
  196. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/element.py +0 -0
  197. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/enums.py +0 -0
  198. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/error.py +0 -0
  199. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/member.py +0 -0
  200. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/message.py +0 -0
  201. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/name.py +0 -0
  202. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/presence.py +0 -0
  203. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/profile.py +0 -0
  204. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/session.py +0 -0
  205. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/sync.py +0 -0
  206. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/domain/user.py +0 -0
  207. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/events/__init__.py +0 -0
  208. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/events/file.py +0 -0
  209. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/events/message.py +0 -0
  210. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/src/pymax/types/events/video.py +0 -0
  211. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/__init__.py +0 -0
  212. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/api/test_auth_service.py +0 -0
  213. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/api/test_message_service.py +0 -0
  214. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/api/test_upload_service.py +0 -0
  215. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/auth/test_auth_flows.py +0 -0
  216. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/conftest.py +0 -0
  217. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/connection/test_connection.py +0 -0
  218. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/dispatch/test_dispatcher.py +0 -0
  219. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/domain/test_bound_models.py +0 -0
  220. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/files/test_files_and_formatting.py +0 -0
  221. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/protocol/test_protocols.py +0 -0
  222. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/session/test_store.py +0 -0
  223. {maxapi_python-2.1.0 → maxapi_python-2.1.2}/tests/telemetry/test_telemetry.py +0 -0
@@ -0,0 +1,64 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: release-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ package:
17
+ name: Build package
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - name: Checkout repository
22
+ uses: actions/checkout@v6
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v8.1.0
26
+ with:
27
+ enable-cache: true
28
+
29
+ - name: Build package distributions
30
+ run: uv build
31
+
32
+ - name: Validate package distributions
33
+ run: uv run twine check dist/*
34
+
35
+ - name: Upload package distributions
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: package-distributions
39
+ path: dist/
40
+
41
+ publish:
42
+ name: Publish to PyPI
43
+ runs-on: ubuntu-latest
44
+ needs: [package]
45
+
46
+ environment:
47
+ name: pypi
48
+
49
+ permissions:
50
+ contents: read
51
+ id-token: write
52
+
53
+ steps:
54
+ - name: Download package distributions
55
+ uses: actions/download-artifact@v4
56
+ with:
57
+ name: package-distributions
58
+ path: dist/
59
+
60
+ - name: Install uv
61
+ uses: astral-sh/setup-uv@v8.1.0
62
+
63
+ - name: Publish package to PyPI
64
+ run: uv publish
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxapi-python
3
- Version: 2.1.0
3
+ Version: 2.1.2
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,21 +32,26 @@ Account
32
32
  Фотография профиля
33
33
  ------------------
34
34
 
35
- Сейчас ``change_profile(photo=...)`` не загружает файл напрямую. Для фото
36
- нужен ``photo_token`` от API Max:
35
+ Передайте ``Photo`` в ``change_profile(photo=...)``, чтобы PyMax сам загрузил
36
+ файл и применил новый токен фотографии:
37
37
 
38
38
  .. code-block:: python
39
39
 
40
- upload_url = await client.request_profile_photo_upload_url()
41
- print(upload_url)
40
+ from pymax import Photo
42
41
 
43
42
  await client.change_profile(
44
43
  first_name="Alex",
45
- photo_token="PHOTO_TOKEN",
44
+ photo=Photo(path="avatar.jpg"),
46
45
  )
47
46
 
48
- Если передать ``photo`` вместо ``photo_token``, PyMax выбросит
49
- ``NotImplementedError``.
47
+ Если у вас уже есть токен фотографии от API Max, его можно передать напрямую:
48
+
49
+ .. code-block:: python
50
+
51
+ await client.change_profile(
52
+ first_name="Alex",
53
+ photo_token="PHOTO_TOKEN",
54
+ )
50
55
 
51
56
  Папки чатов
52
57
  -----------
@@ -118,9 +123,9 @@ Account
118
123
  ``on_start`` или после успешного ``await client.start()`` в собственном
119
124
  lifecycle.
120
125
 
121
- ``NotImplementedError`` при ``change_profile(photo=...)``
122
- Прямая загрузка фото через параметр ``photo`` пока не реализована.
123
- Используйте ``photo_token``.
126
+ Фото профиля не обновилось
127
+ Если переданы и ``photo``, и ``photo_token``, PyMax загрузит ``photo`` и
128
+ использует новый токен загруженной фотографии.
124
129
 
125
130
  Папка создалась, но список старый
126
131
  Используйте ``get_folders()`` после изменения и сохраняйте новый
@@ -22,6 +22,8 @@ PyMax - асинхронная Python-библиотека для Max API. Он
22
22
  :maxdepth: 1
23
23
  :caption: Новости
24
24
 
25
+ release-2-1-2
26
+ release-2-1-1
25
27
  release-2-1-0
26
28
 
27
29
  .. toctree::
@@ -0,0 +1,16 @@
1
+ PyMax 2.1.1
2
+ ===========
3
+
4
+ Изменения относительно ``2.1.0``.
5
+
6
+ Добавлено
7
+ ---------
8
+
9
+ * ``change_profile(photo=...)`` теперь загружает фотографию профиля напрямую.
10
+
11
+ Исправлено
12
+ ----------
13
+
14
+ * TLS-handshake при TCP-подключении через proxy передает ``server_hostname``.
15
+ * Локальный токен обновляется после ``close_all_sessions()`` и при получении
16
+ нового токена во время handshake.
@@ -0,0 +1,32 @@
1
+ PyMax 2.1.2
2
+ ===========
3
+
4
+ Изменения относительно ``2.1.1``.
5
+
6
+ Добавлено
7
+ ---------
8
+
9
+ * ``get_bot_init_data()`` теперь можно вызвать без ``chat_id`` для сценариев,
10
+ где Max запускает web app вне конкретного чата.
11
+
12
+ Исправлено
13
+ ----------
14
+
15
+ * ``ExtraConfig.request_timeout`` снова применяется к API-запросам по
16
+ умолчанию, а явный ``timeout`` в низкоуровневом вызове сохраняет приоритет.
17
+ * Login-ответ без нового ``token`` больше не ломает запуск клиента и не
18
+ перезаписывает сохраненный токен пустым значением.
19
+ * ``FolderList`` больше не переопределяет pydantic-итератор и не ломает
20
+ ``dict(...)`` / стандартную сериализацию модели.
21
+
22
+ Изменилось
23
+ ----------
24
+
25
+ * Publish workflow упрощен: сборка, проверка дистрибутивов и публикация в PyPI
26
+ теперь разделены на понятные шаги с artifact handoff.
27
+
28
+ Миграция
29
+ --------
30
+
31
+ * Если код итерировал ``FolderList`` напрямую, замените это на
32
+ ``folder_list.folders``.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "maxapi-python"
3
- version = "2.1.0"
3
+ version = "2.1.2"
4
4
  description = "Python wrapper для API мессенджера Max"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,4 +1,4 @@
1
- __version__ = "2.1.0"
1
+ __version__ = "2.1.2"
2
2
 
3
3
 
4
4
  from .auth import (
@@ -3,5 +3,5 @@ from pymax.api.models import CamelModel
3
3
 
4
4
  class RequestInitDataPayload(CamelModel):
5
5
  bot_id: int
6
- chat_id: int
6
+ chat_id: int | None = None
7
7
  start_param: str | None = None
@@ -23,13 +23,9 @@ class BotsService:
23
23
  async def get_init_data(
24
24
  self,
25
25
  bot_id: int,
26
- chat_id: int,
26
+ chat_id: int | None = None,
27
27
  start_param: str | None = None,
28
28
  ) -> InitData:
29
- frame = RequestInitDataPayload(
30
- bot_id=bot_id, chat_id=chat_id, start_param=start_param
31
- )
32
- response = await self.app.invoke(
33
- Opcode.WEB_APP_INIT_DATA, frame.to_payload()
34
- )
29
+ frame = RequestInitDataPayload(bot_id=bot_id, chat_id=chat_id, start_param=start_param)
30
+ response = await self.app.invoke(Opcode.WEB_APP_INIT_DATA, frame.to_payload())
35
31
  return require_payload_model(response, InitData)
@@ -9,6 +9,7 @@ from pymax.api.response import (
9
9
  require_payload_item_model,
10
10
  require_payload_model,
11
11
  )
12
+ from pymax.files import Photo
12
13
  from pymax.logging import get_logger
13
14
  from pymax.protocol import Opcode
14
15
  from pymax.types.domain import FolderList, FolderUpdate, Profile
@@ -47,15 +48,20 @@ class SelfService:
47
48
  first_name: str,
48
49
  last_name: str | None = None,
49
50
  description: str | None = None,
50
- photo: Any | None = None,
51
+ photo: Photo | None = None,
51
52
  *,
52
53
  photo_token: str | None = None,
53
54
  ) -> bool:
54
55
  if photo is not None:
55
- raise NotImplementedError(
56
- "Profile photo upload is not implemented without upload infra. "
57
- "Pass photo_token instead."
56
+ attach = await self.app.api.uploads.upload_photo(
57
+ photo, profile=True
58
58
  )
59
+ if photo_token:
60
+ logger.warning(
61
+ "photo_token argument was provided but will be overridden by the uploaded photo token"
62
+ )
63
+
64
+ photo_token = attach.photo_token
59
65
 
60
66
  frame = ChangeProfilePayload(
61
67
  first_name=first_name,
@@ -145,6 +151,7 @@ class SelfService:
145
151
  return False
146
152
 
147
153
  await self.app.store.update_token(self.app.session.token, token)
154
+ self.app.session.token = token
148
155
 
149
156
  return True
150
157
 
@@ -51,11 +51,13 @@ class UploadService:
51
51
  self.on_file_attach
52
52
  )
53
53
 
54
- async def upload_photo(self, photo: Photo) -> AttachPhotoPayload:
54
+ async def upload_photo(
55
+ self, photo: Photo, profile: bool = False
56
+ ) -> AttachPhotoPayload:
55
57
  logger.info("Uploading photo")
56
58
  logger.debug("Preparing photo upload payload")
57
59
 
58
- payload = UploadPayload().model_dump()
60
+ payload = UploadPayload(profile=profile).model_dump()
59
61
 
60
62
  try:
61
63
  data = await self.app.invoke(
@@ -33,9 +33,7 @@ class App(Generic[ClientT]):
33
33
  self.dispatcher: Dispatcher[ClientT] = Dispatcher(self, root_router)
34
34
  self.api = ApiFacade(self)
35
35
  self.config = config
36
- self.store = self.config.store or SessionStore(
37
- config.work_dir, config.session_name
38
- )
36
+ self.store = self.config.store or SessionStore(config.work_dir, config.session_name)
39
37
  self.auth_flow = auth_flow
40
38
 
41
39
  self.me: Profile | None = None
@@ -76,18 +74,14 @@ class App(Generic[ClientT]):
76
74
  await self.connection.open()
77
75
 
78
76
  handshake_device_id = (
79
- session_data.device_id
80
- if session_data
81
- else self.config.device.device_id
77
+ session_data.device_id if session_data else self.config.device.device_id
82
78
  )
83
79
  logger.debug("running handshake")
84
80
  await self.handshake(handshake_device_id)
85
81
  except (ConnectionError, EOFError, OSError, TimeoutError) as e:
86
82
  logger.exception("failed to connect or handshake")
87
83
  await self.connection.close()
88
- raise ConnectionError(
89
- f"Failed to connect and handshake: {e}"
90
- ) from e
84
+ raise ConnectionError(f"Failed to connect and handshake: {e}") from e
91
85
 
92
86
  self._ping_task = asyncio.create_task(self._ping_loop())
93
87
 
@@ -108,9 +102,7 @@ class App(Generic[ClientT]):
108
102
 
109
103
  if not auth_result.token:
110
104
  logger.error("authentication finished without token")
111
- raise RuntimeError(
112
- "Authentication failed: no token received"
113
- )
105
+ raise RuntimeError("Authentication failed: no token received")
114
106
 
115
107
  await self.store.save_session(
116
108
  session_data := SessionInfo(
@@ -135,6 +127,10 @@ class App(Generic[ClientT]):
135
127
  self.config.device.user_agent,
136
128
  )
137
129
 
130
+ if response.token is not None and response.token != self.session.token:
131
+ await self.store.update_token(self.session.token, response.token)
132
+ self.session.token = response.token
133
+
138
134
  self.me = response.profile
139
135
  self.chats = response.chats
140
136
  self.users[self.me.contact.id] = self.me.contact
@@ -185,7 +181,7 @@ class App(Generic[ClientT]):
185
181
  opcode: int,
186
182
  payload: dict[str, Any],
187
183
  cmd: int = Command.REQUEST,
188
- timeout: float | None = 30.0,
184
+ timeout: float | None = None,
189
185
  compress: bool = False,
190
186
  ) -> InboundFrame:
191
187
  seq = self.connection.next_seq()
@@ -207,10 +203,11 @@ class App(Generic[ClientT]):
207
203
  payload_keys,
208
204
  )
209
205
  logger.debug("Request data=%s", frame.model_dump())
210
- response = await self.connection.request(frame, timeout=timeout)
211
- response_keys = (
212
- sorted(response.payload.keys()) if response.payload else []
206
+ request_timeout = (
207
+ self.config.request_timeout if timeout is None else timeout
213
208
  )
209
+ response = await self.connection.request(frame, timeout=request_timeout)
210
+ response_keys = sorted(response.payload.keys()) if response.payload else []
214
211
  logger.debug(
215
212
  "response opcode=%s cmd=%s seq=%s payload_keys=%s",
216
213
  response.opcode,
@@ -29,17 +29,13 @@ class SelfMixin(IClientProtocol):
29
29
  first_name: Имя профиля.
30
30
  last_name: Фамилия профиля.
31
31
  description: Описание профиля.
32
- photo: Файл или объект фото. Прямая загрузка через этот
33
- параметр пока не реализована.
32
+ photo: Файл или объект фото, который нужно загрузить как новую
33
+ фотографию профиля.
34
34
  photo_token: Токен фотографии, уже загруженной через API Max.
35
35
 
36
36
  Returns:
37
37
  ``True`` после успешного обновления. Клиент также обновит
38
38
  ``client.me`` и кеш текущего контакта.
39
-
40
- Raises:
41
- NotImplementedError: Если передан ``photo`` вместо
42
- ``photo_token``.
43
39
  """
44
40
  return await self._app.api.account.change_profile(
45
41
  first_name=first_name,
@@ -33,10 +33,12 @@ class TCPTransport(Transport):
33
33
  sock = await proxy.connect(
34
34
  dest_host=self._host,
35
35
  dest_port=self._port,
36
- ssl=self._use_ssl,
37
36
  )
37
+ server_hostname = self._host if self._use_ssl else None
38
38
  self._reader, self._writer = await asyncio.open_connection(
39
- sock=sock, ssl=self._use_ssl
39
+ sock=sock,
40
+ ssl=self._use_ssl,
41
+ server_hostname=server_hostname,
40
42
  )
41
43
  logger.info(
42
44
  "tcp connected via proxy %s host=%s port=%s ssl=%s",
@@ -1,8 +1,6 @@
1
- from collections.abc import Iterator
2
1
  from typing import Any
3
2
 
4
3
  from pydantic import Field
5
- from typing_extensions import override
6
4
 
7
5
  from .base import CamelModel
8
6
 
@@ -68,7 +66,3 @@ class FolderList(CamelModel):
68
66
  folders: list[Folder] = Field(default_factory=list)
69
67
  all_filter_exclude_folders: list[Any] = Field(default_factory=list)
70
68
  folder_sync: int = 0
71
-
72
- @override
73
- def __iter__(self) -> Iterator[Folder]: # pyright: ignore[reportIncompatibleMethodOverride]
74
- yield from self.folders
@@ -16,11 +16,9 @@ class LoginConfig(CamelModel):
16
16
  class LoginResponse(CamelModel):
17
17
  chats: list[Chat] = Field(default_factory=list)
18
18
  profile: Profile
19
- messages: dict[int, list[Message]] = Field(
20
- default_factory=dict
21
- ) # chat_id -> [message]
19
+ messages: dict[int, list[Message]] = Field(default_factory=dict) # chat_id -> [message]
22
20
  contacts: list[User | None] = Field(default_factory=list)
23
- token: str
21
+ token: str | None = None
24
22
  time: int | None = None
25
23
  config: LoginConfig | None = None
26
24
 
@@ -29,19 +27,9 @@ class LoginResponse(CamelModel):
29
27
  config_hash = self.config.hash if self.config is not None else None
30
28
 
31
29
  return SyncState(
32
- chats_sync=(
33
- sync_time if sync_time is not None else current.chats_sync
34
- ),
35
- contacts_sync=(
36
- sync_time if sync_time is not None else current.contacts_sync
37
- ),
38
- drafts_sync=(
39
- sync_time if sync_time is not None else current.drafts_sync
40
- ),
41
- presence_sync=(
42
- sync_time if sync_time is not None else current.presence_sync
43
- ),
44
- config_hash=(
45
- config_hash if config_hash is not None else current.config_hash
46
- ),
30
+ chats_sync=(sync_time if sync_time is not None else current.chats_sync),
31
+ contacts_sync=(sync_time if sync_time is not None else current.contacts_sync),
32
+ drafts_sync=(sync_time if sync_time is not None else current.drafts_sync),
33
+ presence_sync=(sync_time if sync_time is not None else current.presence_sync),
34
+ config_hash=(config_hash if config_hash is not None else current.config_hash),
47
35
  )
@@ -345,7 +345,7 @@ async def test_self_service_profile_photo_folders_and_logout() -> None:
345
345
 
346
346
  assert created.folder is not None
347
347
  assert created.folder.title == "Work"
348
- assert [folder.id for folder in folders] == ["folder-1"]
348
+ assert [folder.id for folder in folders.folders] == ["folder-1"]
349
349
  assert updated.folder is not None
350
350
  assert updated.folder.title == "New"
351
351
  assert deleted.folder_sync == 4
@@ -150,3 +150,21 @@ async def test_app_invoke_turns_error_frames_into_api_error() -> None:
150
150
  assert exc_info.value.error == "rate_limited"
151
151
  assert exc_info.value.opcode == Opcode.PING
152
152
  assert connection.sent[0][0].seq == 0
153
+
154
+
155
+ @pytest.mark.asyncio
156
+ async def test_app_invoke_uses_config_timeout_and_allows_override() -> None:
157
+ store = RuntimeStore(
158
+ SessionInfo(token="token", device_id="dev", phone="+7")
159
+ )
160
+ config = make_config().model_copy(
161
+ update={"request_timeout": 12.5, "store": store}
162
+ )
163
+ connection = RuntimeConnection([frame({}), frame({})])
164
+ app: App[object] = App(connection, config, StaticAuthFlow())
165
+
166
+ await app.invoke(Opcode.PING, {"interactive": True})
167
+ await app.invoke(Opcode.PING, {"interactive": True}, timeout=3.0)
168
+
169
+ assert connection.sent[0][1] == 12.5
170
+ assert connection.sent[1][1] == 3.0
@@ -104,6 +104,53 @@ async def test_tcp_transport_connect_send_recv_and_close(
104
104
  assert writer.closed is True
105
105
 
106
106
 
107
+ @pytest.mark.asyncio
108
+ async def test_tcp_transport_proxy_ssl_passes_server_hostname(
109
+ monkeypatch: pytest.MonkeyPatch,
110
+ ) -> None:
111
+ reader = FakeStreamReader()
112
+ writer = FakeStreamWriter()
113
+ sock = object()
114
+ proxy_connect_kwargs = {}
115
+ open_connection_kwargs = {}
116
+
117
+ class FakeProxy:
118
+ async def connect(self, **kwargs):
119
+ proxy_connect_kwargs.update(kwargs)
120
+ return sock
121
+
122
+ async def open_connection(*args, **kwargs):
123
+ open_connection_kwargs.update(kwargs)
124
+ return reader, writer
125
+
126
+ monkeypatch.setattr(
127
+ "pymax.transport.tcp.Proxy.from_url",
128
+ lambda proxy_url: FakeProxy(),
129
+ )
130
+ monkeypatch.setattr(
131
+ "pymax.transport.tcp.asyncio.open_connection", open_connection
132
+ )
133
+
134
+ transport = TCPTransport(
135
+ "example.test",
136
+ 443,
137
+ proxy="socks5://localhost:9050",
138
+ use_ssl=True,
139
+ )
140
+
141
+ await transport.connect()
142
+
143
+ assert proxy_connect_kwargs == {
144
+ "dest_host": "example.test",
145
+ "dest_port": 443,
146
+ }
147
+ assert open_connection_kwargs == {
148
+ "sock": sock,
149
+ "ssl": True,
150
+ "server_hostname": "example.test",
151
+ }
152
+
153
+
107
154
  class FakeWebSocket:
108
155
  def __init__(self) -> None:
109
156
  self.close_code = None
@@ -1033,7 +1033,7 @@ wheels = [
1033
1033
 
1034
1034
  [[package]]
1035
1035
  name = "maxapi-python"
1036
- version = "2.1.0"
1036
+ version = "2.1.2"
1037
1037
  source = { editable = "." }
1038
1038
  dependencies = [
1039
1039
  { name = "aiofiles" },
@@ -1,84 +0,0 @@
1
- name: Upload Python Package
2
-
3
- on:
4
- release:
5
- types: [published]
6
- workflow_dispatch:
7
-
8
- permissions:
9
- contents: read
10
-
11
- jobs:
12
- release-checks:
13
- runs-on: ubuntu-latest
14
-
15
- steps:
16
- - uses: actions/checkout@v4
17
- with:
18
- persist-credentials: false
19
-
20
- - name: Set up uv
21
- uses: astral-sh/setup-uv@v4
22
- with:
23
- python-version: "3.10"
24
- enable-cache: true
25
-
26
- - name: Check lint
27
- run: uv run ruff check src tests
28
-
29
- - name: Check formatting
30
- run: uv run ruff format --check src tests
31
-
32
- - name: Run tests
33
- run: uv run pytest
34
-
35
- - name: Build docs
36
- run: uv run sphinx-build -b html docs /tmp/pymax-docs
37
-
38
- release-build:
39
- runs-on: ubuntu-latest
40
- needs: release-checks
41
-
42
- steps:
43
- - uses: actions/checkout@v4
44
- with:
45
- persist-credentials: false
46
-
47
- - name: Set up uv
48
- uses: astral-sh/setup-uv@v4
49
- with:
50
- python-version: "3.10"
51
- enable-cache: true
52
-
53
- - name: Build release distributions
54
- run: uv build
55
-
56
- - name: Check distributions
57
- run: uv run twine check dist/*
58
-
59
- - name: Upload distributions
60
- uses: actions/upload-artifact@v4
61
- with:
62
- name: release-dists
63
- path: dist/
64
-
65
- pypi-publish:
66
- runs-on: ubuntu-latest
67
- needs: release-build
68
- environment:
69
- name: pypi
70
- url: https://pypi.org/project/maxapi-python/
71
-
72
- permissions:
73
- contents: read
74
- id-token: write
75
-
76
- steps:
77
- - name: Retrieve release distributions
78
- uses: actions/download-artifact@v4
79
- with:
80
- name: release-dists
81
- path: dist/
82
-
83
- - name: Publish release distributions to PyPI
84
- uses: pypa/gh-action-pypi-publish@release/v1
File without changes
File without changes
File without changes