pylzt 0.1.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.
Files changed (402) hide show
  1. pylzt-0.1.0/.gitattributes +1 -0
  2. pylzt-0.1.0/.githooks/pre-push +18 -0
  3. pylzt-0.1.0/.github/workflows/ci.yml +41 -0
  4. pylzt-0.1.0/.github/workflows/release.yml +94 -0
  5. pylzt-0.1.0/.gitignore +38 -0
  6. pylzt-0.1.0/.pre-commit-config.yaml +32 -0
  7. pylzt-0.1.0/LICENSE +21 -0
  8. pylzt-0.1.0/PKG-INFO +344 -0
  9. pylzt-0.1.0/README.en.md +312 -0
  10. pylzt-0.1.0/README.md +322 -0
  11. pylzt-0.1.0/dev/codegen/_MODULE.md +94 -0
  12. pylzt-0.1.0/dev/codegen/__init__.py +12 -0
  13. pylzt-0.1.0/dev/codegen/__main__.py +116 -0
  14. pylzt-0.1.0/dev/codegen/diff.py +143 -0
  15. pylzt-0.1.0/dev/codegen/generator.py +1670 -0
  16. pylzt-0.1.0/dev/codegen/pipeline.py +281 -0
  17. pylzt-0.1.0/dev/codegen/scraper.py +202 -0
  18. pylzt-0.1.0/dev/generated/openapi/lzt_antipublic.json +828 -0
  19. pylzt-0.1.0/dev/generated/openapi/lzt_forum.json +15215 -0
  20. pylzt-0.1.0/dev/generated/openapi/lzt_market.json +51839 -0
  21. pylzt-0.1.0/dist/.gitignore +1 -0
  22. pylzt-0.1.0/docs/codegen-runbook.en.md +225 -0
  23. pylzt-0.1.0/docs/codegen-runbook.md +276 -0
  24. pylzt-0.1.0/docs/for_ai/index.en.md +49 -0
  25. pylzt-0.1.0/docs/for_ai/index.md +60 -0
  26. pylzt-0.1.0/docs/integration-guide.en.md +366 -0
  27. pylzt-0.1.0/docs/integration-guide.md +367 -0
  28. pylzt-0.1.0/pyproject.toml +100 -0
  29. pylzt-0.1.0/src/pylzt/__init__.py +139 -0
  30. pylzt-0.1.0/src/pylzt/__main__.py +50 -0
  31. pylzt-0.1.0/src/pylzt/client.py +485 -0
  32. pylzt-0.1.0/src/pylzt/config.py +69 -0
  33. pylzt-0.1.0/src/pylzt/enums/__init__.py +0 -0
  34. pylzt-0.1.0/src/pylzt/enums/antipublic.py +41 -0
  35. pylzt-0.1.0/src/pylzt/enums/forum.py +136 -0
  36. pylzt-0.1.0/src/pylzt/enums/market.py +497 -0
  37. pylzt-0.1.0/src/pylzt/errors.py +342 -0
  38. pylzt-0.1.0/src/pylzt/export/__init__.py +0 -0
  39. pylzt-0.1.0/src/pylzt/export/resumable_exporter.py +51 -0
  40. pylzt-0.1.0/src/pylzt/facades/__init__.py +0 -0
  41. pylzt-0.1.0/src/pylzt/facades/_namespace.py +122 -0
  42. pylzt-0.1.0/src/pylzt/facades/_sync_namespace.py +77 -0
  43. pylzt-0.1.0/src/pylzt/facades/antipublic.py +145 -0
  44. pylzt-0.1.0/src/pylzt/facades/forum.py +2211 -0
  45. pylzt-0.1.0/src/pylzt/facades/market.py +5429 -0
  46. pylzt-0.1.0/src/pylzt/facades/sync_antipublic.py +140 -0
  47. pylzt-0.1.0/src/pylzt/facades/sync_forum.py +2148 -0
  48. pylzt-0.1.0/src/pylzt/facades/sync_market.py +5340 -0
  49. pylzt-0.1.0/src/pylzt/lib/__init__.py +1 -0
  50. pylzt-0.1.0/src/pylzt/lib/asyncio_utils.py +23 -0
  51. pylzt-0.1.0/src/pylzt/lib/batch.py +399 -0
  52. pylzt-0.1.0/src/pylzt/lib/cache.py +65 -0
  53. pylzt-0.1.0/src/pylzt/lib/clock.py +48 -0
  54. pylzt-0.1.0/src/pylzt/lib/concurrency.py +72 -0
  55. pylzt-0.1.0/src/pylzt/lib/media_storage.py +83 -0
  56. pylzt-0.1.0/src/pylzt/lib/metrics.py +36 -0
  57. pylzt-0.1.0/src/pylzt/lib/retry.py +60 -0
  58. pylzt-0.1.0/src/pylzt/media.py +31 -0
  59. pylzt-0.1.0/src/pylzt/methods/__init__.py +1 -0
  60. pylzt-0.1.0/src/pylzt/methods/antipublic_account.py +58 -0
  61. pylzt-0.1.0/src/pylzt/methods/antipublic_check.py +32 -0
  62. pylzt-0.1.0/src/pylzt/methods/antipublic_info.py +42 -0
  63. pylzt-0.1.0/src/pylzt/methods/antipublic_search.py +72 -0
  64. pylzt-0.1.0/src/pylzt/methods/balances.py +66 -0
  65. pylzt-0.1.0/src/pylzt/methods/base.py +177 -0
  66. pylzt-0.1.0/src/pylzt/methods/catalog.py +79 -0
  67. pylzt-0.1.0/src/pylzt/methods/categories.py +67 -0
  68. pylzt-0.1.0/src/pylzt/methods/conversations.py +47 -0
  69. pylzt-0.1.0/src/pylzt/methods/forum_assets.py +31 -0
  70. pylzt-0.1.0/src/pylzt/methods/forum_authentication.py +31 -0
  71. pylzt-0.1.0/src/pylzt/methods/forum_batch_requests.py +50 -0
  72. pylzt-0.1.0/src/pylzt/methods/forum_categories.py +61 -0
  73. pylzt-0.1.0/src/pylzt/methods/forum_chatbox.py +159 -0
  74. pylzt-0.1.0/src/pylzt/methods/forum_content_tagging.py +102 -0
  75. pylzt-0.1.0/src/pylzt/methods/forum_conversations.py +426 -0
  76. pylzt-0.1.0/src/pylzt/methods/forum_forms.py +47 -0
  77. pylzt-0.1.0/src/pylzt/methods/forum_forums.py +148 -0
  78. pylzt-0.1.0/src/pylzt/methods/forum_link_forums.py +52 -0
  79. pylzt-0.1.0/src/pylzt/methods/forum_notifications.py +56 -0
  80. pylzt-0.1.0/src/pylzt/methods/forum_pages.py +59 -0
  81. pylzt-0.1.0/src/pylzt/methods/forum_post_comments.py +38 -0
  82. pylzt-0.1.0/src/pylzt/methods/forum_posts.py +137 -0
  83. pylzt-0.1.0/src/pylzt/methods/forum_profile_post_comments.py +89 -0
  84. pylzt-0.1.0/src/pylzt/methods/forum_profile_posts.py +159 -0
  85. pylzt-0.1.0/src/pylzt/methods/forum_searching.py +227 -0
  86. pylzt-0.1.0/src/pylzt/methods/forum_threads.py +549 -0
  87. pylzt-0.1.0/src/pylzt/methods/forum_users.py +493 -0
  88. pylzt-0.1.0/src/pylzt/methods/market_account_managing.py +24 -0
  89. pylzt-0.1.0/src/pylzt/methods/market_account_publishing.py +194 -0
  90. pylzt-0.1.0/src/pylzt/methods/market_account_purchasing.py +112 -0
  91. pylzt-0.1.0/src/pylzt/methods/market_accounts_list.py +305 -0
  92. pylzt-0.1.0/src/pylzt/methods/market_accounts_managing.py +760 -0
  93. pylzt-0.1.0/src/pylzt/methods/market_batch_requests.py +50 -0
  94. pylzt-0.1.0/src/pylzt/methods/market_cart.py +72 -0
  95. pylzt-0.1.0/src/pylzt/methods/market_category_search.py +2638 -0
  96. pylzt-0.1.0/src/pylzt/methods/market_custom_discounts.py +24 -0
  97. pylzt-0.1.0/src/pylzt/methods/market_imap.py +29 -0
  98. pylzt-0.1.0/src/pylzt/methods/market_invoices.py +64 -0
  99. pylzt-0.1.0/src/pylzt/methods/market_payments.py +188 -0
  100. pylzt-0.1.0/src/pylzt/methods/market_profile.py +31 -0
  101. pylzt-0.1.0/src/pylzt/methods/market_proxy.py +25 -0
  102. pylzt-0.1.0/src/pylzt/methods/market_tags.py +45 -0
  103. pylzt-0.1.0/src/pylzt/methods/notifications.py +50 -0
  104. pylzt-0.1.0/src/pylzt/methods/payments.py +29 -0
  105. pylzt-0.1.0/src/pylzt/methods/users.py +28 -0
  106. pylzt-0.1.0/src/pylzt/models/__init__.py +1 -0
  107. pylzt-0.1.0/src/pylzt/models/antipublic/__init__.py +14 -0
  108. pylzt-0.1.0/src/pylzt/models/antipublic/extended_stats.py +19 -0
  109. pylzt-0.1.0/src/pylzt/models/antipublic/public_count_lines_response.py +19 -0
  110. pylzt-0.1.0/src/pylzt/models/antipublic/threads.py +19 -0
  111. pylzt-0.1.0/src/pylzt/models/balance.py +27 -0
  112. pylzt-0.1.0/src/pylzt/models/base.py +74 -0
  113. pylzt-0.1.0/src/pylzt/models/category.py +19 -0
  114. pylzt-0.1.0/src/pylzt/models/conversation.py +85 -0
  115. pylzt-0.1.0/src/pylzt/models/forum/__init__.py +212 -0
  116. pylzt-0.1.0/src/pylzt/models/forum/categories_list_response.py +19 -0
  117. pylzt-0.1.0/src/pylzt/models/forum/category.py +25 -0
  118. pylzt-0.1.0/src/pylzt/models/forum/category_links.py +22 -0
  119. pylzt-0.1.0/src/pylzt/models/forum/category_permissions.py +19 -0
  120. pylzt-0.1.0/src/pylzt/models/forum/chatbox_index_response.py +24 -0
  121. pylzt-0.1.0/src/pylzt/models/forum/claim.py +26 -0
  122. pylzt-0.1.0/src/pylzt/models/forum/content.py +55 -0
  123. pylzt-0.1.0/src/pylzt/models/forum/content_contest.py +37 -0
  124. pylzt-0.1.0/src/pylzt/models/forum/content_first_post.py +49 -0
  125. pylzt-0.1.0/src/pylzt/models/forum/content_links.py +26 -0
  126. pylzt-0.1.0/src/pylzt/models/forum/content_permissions.py +23 -0
  127. pylzt-0.1.0/src/pylzt/models/forum/content_thread_prefixe.py +18 -0
  128. pylzt-0.1.0/src/pylzt/models/forum/contest_permissions.py +19 -0
  129. pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_edit_message.py +41 -0
  130. pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message.py +38 -0
  131. pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message_links.py +20 -0
  132. pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message_permissions.py +22 -0
  133. pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_response.py +23 -0
  134. pylzt-0.1.0/src/pylzt/models/forum/conversations_search_response.py +21 -0
  135. pylzt-0.1.0/src/pylzt/models/forum/data_data_total_links_response.py +20 -0
  136. pylzt-0.1.0/src/pylzt/models/forum/field_choice.py +18 -0
  137. pylzt-0.1.0/src/pylzt/models/forum/field_field_choices.py +18 -0
  138. pylzt-0.1.0/src/pylzt/models/forum/first_post_delete_info.py +21 -0
  139. pylzt-0.1.0/src/pylzt/models/forum/first_post_links.py +23 -0
  140. pylzt-0.1.0/src/pylzt/models/forum/first_post_permissions.py +25 -0
  141. pylzt-0.1.0/src/pylzt/models/forum/form.py +21 -0
  142. pylzt-0.1.0/src/pylzt/models/forum/form_field.py +26 -0
  143. pylzt-0.1.0/src/pylzt/models/forum/forms_create_response.py +19 -0
  144. pylzt-0.1.0/src/pylzt/models/forum/forms_list_response.py +21 -0
  145. pylzt-0.1.0/src/pylzt/models/forum/forum.py +39 -0
  146. pylzt-0.1.0/src/pylzt/models/forum/forum_feed_option.py +37 -0
  147. pylzt-0.1.0/src/pylzt/models/forum/forum_forum_prefixe.py +19 -0
  148. pylzt-0.1.0/src/pylzt/models/forum/forum_links.py +24 -0
  149. pylzt-0.1.0/src/pylzt/models/forum/forum_permissions.py +22 -0
  150. pylzt-0.1.0/src/pylzt/models/forum/forum_prefixe_group_prefixe.py +19 -0
  151. pylzt-0.1.0/src/pylzt/models/forum/forum_status_message_response.py +17 -0
  152. pylzt-0.1.0/src/pylzt/models/forum/forums_get_feed_options_response.py +19 -0
  153. pylzt-0.1.0/src/pylzt/models/forum/forums_grouped_response.py +21 -0
  154. pylzt-0.1.0/src/pylzt/models/forum/forums_list_response.py +21 -0
  155. pylzt-0.1.0/src/pylzt/models/forum/forums_list_tab.py +18 -0
  156. pylzt-0.1.0/src/pylzt/models/forum/ignore.py +56 -0
  157. pylzt-0.1.0/src/pylzt/models/forum/ignore_custom_fields.py +34 -0
  158. pylzt-0.1.0/src/pylzt/models/forum/ignore_rendered.py +22 -0
  159. pylzt-0.1.0/src/pylzt/models/forum/leaderboard.py +39 -0
  160. pylzt-0.1.0/src/pylzt/models/forum/leaderboard_rendered.py +20 -0
  161. pylzt-0.1.0/src/pylzt/models/forum/leaderboard_uniq_banner.py +19 -0
  162. pylzt-0.1.0/src/pylzt/models/forum/link_forum.py +26 -0
  163. pylzt-0.1.0/src/pylzt/models/forum/link_forum_links.py +18 -0
  164. pylzt-0.1.0/src/pylzt/models/forum/links.py +19 -0
  165. pylzt-0.1.0/src/pylzt/models/forum/links_list_response.py +21 -0
  166. pylzt-0.1.0/src/pylzt/models/forum/message.py +27 -0
  167. pylzt-0.1.0/src/pylzt/models/forum/message_links.py +20 -0
  168. pylzt-0.1.0/src/pylzt/models/forum/message_permissions.py +24 -0
  169. pylzt-0.1.0/src/pylzt/models/forum/message_recipient.py +23 -0
  170. pylzt-0.1.0/src/pylzt/models/forum/message_room.py +21 -0
  171. pylzt-0.1.0/src/pylzt/models/forum/o_auth_token_response.py +28 -0
  172. pylzt-0.1.0/src/pylzt/models/forum/page.py +25 -0
  173. pylzt-0.1.0/src/pylzt/models/forum/page_links.py +21 -0
  174. pylzt-0.1.0/src/pylzt/models/forum/pages_list_response.py +19 -0
  175. pylzt-0.1.0/src/pylzt/models/forum/permissions.py +23 -0
  176. pylzt-0.1.0/src/pylzt/models/forum/permissions_bump.py +20 -0
  177. pylzt-0.1.0/src/pylzt/models/forum/post.py +48 -0
  178. pylzt-0.1.0/src/pylzt/models/forum/post_thread.py +54 -0
  179. pylzt-0.1.0/src/pylzt/models/forum/profile_thread_links.py +25 -0
  180. pylzt-0.1.0/src/pylzt/models/forum/profile_thread_permissions.py +22 -0
  181. pylzt-0.1.0/src/pylzt/models/forum/rendered_avatars.py +19 -0
  182. pylzt-0.1.0/src/pylzt/models/forum/room.py +20 -0
  183. pylzt-0.1.0/src/pylzt/models/forum/rooms_online.py +22 -0
  184. pylzt-0.1.0/src/pylzt/models/forum/search_all_permissions_bump.py +20 -0
  185. pylzt-0.1.0/src/pylzt/models/forum/search_all_response.py +22 -0
  186. pylzt-0.1.0/src/pylzt/models/forum/search_all_user.py +78 -0
  187. pylzt-0.1.0/src/pylzt/models/forum/stats.py +19 -0
  188. pylzt-0.1.0/src/pylzt/models/forum/stats_market.py +20 -0
  189. pylzt-0.1.0/src/pylzt/models/forum/tab.py +31 -0
  190. pylzt-0.1.0/src/pylzt/models/forum/trophy.py +30 -0
  191. pylzt-0.1.0/src/pylzt/models/forum/trophy_progresse.py +27 -0
  192. pylzt-0.1.0/src/pylzt/models/forum/trophy_progresse_progress.py +22 -0
  193. pylzt-0.1.0/src/pylzt/models/forum/user.py +41 -0
  194. pylzt-0.1.0/src/pylzt/models/forum/user_custom_fields.py +31 -0
  195. pylzt-0.1.0/src/pylzt/models/forum/user_edit_permissions.py +28 -0
  196. pylzt-0.1.0/src/pylzt/models/forum/user_field.py +28 -0
  197. pylzt-0.1.0/src/pylzt/models/forum/user_following_user.py +20 -0
  198. pylzt-0.1.0/src/pylzt/models/forum/user_ignored_info.py +19 -0
  199. pylzt-0.1.0/src/pylzt/models/forum/user_links.py +27 -0
  200. pylzt-0.1.0/src/pylzt/models/forum/user_permissions.py +21 -0
  201. pylzt-0.1.0/src/pylzt/models/forum/user_profile_thread.py +46 -0
  202. pylzt-0.1.0/src/pylzt/models/forum/user_rendered.py +21 -0
  203. pylzt-0.1.0/src/pylzt/models/forum/user_uniq_banner.py +20 -0
  204. pylzt-0.1.0/src/pylzt/models/forum/user_user_external_authentication.py +18 -0
  205. pylzt-0.1.0/src/pylzt/models/forum/user_user_following.py +19 -0
  206. pylzt-0.1.0/src/pylzt/models/forum/user_user_group.py +27 -0
  207. pylzt-0.1.0/src/pylzt/models/forum/users_claims_response.py +20 -0
  208. pylzt-0.1.0/src/pylzt/models/forum/users_ignored_user.py +53 -0
  209. pylzt-0.1.0/src/pylzt/models/forum/users_likes_response.py +23 -0
  210. pylzt-0.1.0/src/pylzt/models/forum/users_list_response.py +21 -0
  211. pylzt-0.1.0/src/pylzt/models/forum/users_sa_reset_response.py +18 -0
  212. pylzt-0.1.0/src/pylzt/models/forum/users_secret_answer_types_data.py +18 -0
  213. pylzt-0.1.0/src/pylzt/models/forum/users_trophies_response.py +20 -0
  214. pylzt-0.1.0/src/pylzt/models/lot.py +152 -0
  215. pylzt-0.1.0/src/pylzt/models/market/__init__.py +262 -0
  216. pylzt-0.1.0/src/pylzt/models/market/author_field.py +21 -0
  217. pylzt-0.1.0/src/pylzt/models/market/author_links.py +25 -0
  218. pylzt-0.1.0/src/pylzt/models/market/author_permissions.py +19 -0
  219. pylzt-0.1.0/src/pylzt/models/market/base_item.py +23 -0
  220. pylzt-0.1.0/src/pylzt/models/market/battle_net_item.py +105 -0
  221. pylzt-0.1.0/src/pylzt/models/market/calculator.py +19 -0
  222. pylzt-0.1.0/src/pylzt/models/market/cart_get_response.py +44 -0
  223. pylzt-0.1.0/src/pylzt/models/market/category_discord_item_seller.py +24 -0
  224. pylzt-0.1.0/src/pylzt/models/market/category_response.py +28 -0
  225. pylzt-0.1.0/src/pylzt/models/market/category_steam_list.py +23 -0
  226. pylzt-0.1.0/src/pylzt/models/market/claim.py +23 -0
  227. pylzt-0.1.0/src/pylzt/models/market/claim_author.py +42 -0
  228. pylzt-0.1.0/src/pylzt/models/market/code_data.py +19 -0
  229. pylzt-0.1.0/src/pylzt/models/market/codes.py +18 -0
  230. pylzt-0.1.0/src/pylzt/models/market/currency_list.py +78 -0
  231. pylzt-0.1.0/src/pylzt/models/market/currency_list_btc.py +20 -0
  232. pylzt-0.1.0/src/pylzt/models/market/currency_list_rub.py +20 -0
  233. pylzt-0.1.0/src/pylzt/models/market/custom_discounts_get_response.py +19 -0
  234. pylzt-0.1.0/src/pylzt/models/market/discord_item.py +98 -0
  235. pylzt-0.1.0/src/pylzt/models/market/discount.py +23 -0
  236. pylzt-0.1.0/src/pylzt/models/market/ea_item.py +114 -0
  237. pylzt-0.1.0/src/pylzt/models/market/email_letters_response.py +19 -0
  238. pylzt-0.1.0/src/pylzt/models/market/epic_games_item.py +112 -0
  239. pylzt-0.1.0/src/pylzt/models/market/escape_from_tarkov_item.py +113 -0
  240. pylzt-0.1.0/src/pylzt/models/market/fortnite_item.py +117 -0
  241. pylzt-0.1.0/src/pylzt/models/market/gifts_item.py +81 -0
  242. pylzt-0.1.0/src/pylzt/models/market/hytale_item.py +94 -0
  243. pylzt-0.1.0/src/pylzt/models/market/instagram_item.py +95 -0
  244. pylzt-0.1.0/src/pylzt/models/market/invoice.py +33 -0
  245. pylzt-0.1.0/src/pylzt/models/market/item_account_link.py +19 -0
  246. pylzt-0.1.0/src/pylzt/models/market/item_apex_legends.py +21 -0
  247. pylzt-0.1.0/src/pylzt/models/market/item_battlenet_game.py +24 -0
  248. pylzt-0.1.0/src/pylzt/models/market/item_battlenet_transaction.py +20 -0
  249. pylzt-0.1.0/src/pylzt/models/market/item_bump_settings.py +20 -0
  250. pylzt-0.1.0/src/pylzt/models/market/item_buyer.py +19 -0
  251. pylzt-0.1.0/src/pylzt/models/market/item_category.py +20 -0
  252. pylzt-0.1.0/src/pylzt/models/market/item_code_data_response.py +20 -0
  253. pylzt-0.1.0/src/pylzt/models/market/item_eg_game.py +27 -0
  254. pylzt-0.1.0/src/pylzt/models/market/item_eg_transaction.py +20 -0
  255. pylzt-0.1.0/src/pylzt/models/market/item_extra_price.py +18 -0
  256. pylzt-0.1.0/src/pylzt/models/market/item_fortnite_past_season.py +28 -0
  257. pylzt-0.1.0/src/pylzt/models/market/item_fortnite_skin.py +21 -0
  258. pylzt-0.1.0/src/pylzt/models/market/item_guarantee.py +25 -0
  259. pylzt-0.1.0/src/pylzt/models/market/item_id_tag_added_tag_id_delete_tags_response.py +22 -0
  260. pylzt-0.1.0/src/pylzt/models/market/item_login_data.py +23 -0
  261. pylzt-0.1.0/src/pylzt/models/market/item_lol_inventory.py +24 -0
  262. pylzt-0.1.0/src/pylzt/models/market/item_public_tag.py +19 -0
  263. pylzt-0.1.0/src/pylzt/models/market/item_r6_operator.py +19 -0
  264. pylzt-0.1.0/src/pylzt/models/market/item_roblox_game_donation.py +19 -0
  265. pylzt-0.1.0/src/pylzt/models/market/item_roblox_game_donations_detail.py +19 -0
  266. pylzt-0.1.0/src/pylzt/models/market/item_seller.py +23 -0
  267. pylzt-0.1.0/src/pylzt/models/market/item_shop_counts.py +20 -0
  268. pylzt-0.1.0/src/pylzt/models/market/item_socialclub_game.py +29 -0
  269. pylzt-0.1.0/src/pylzt/models/market/item_steam_full_games.py +20 -0
  270. pylzt-0.1.0/src/pylzt/models/market/item_steam_transaction.py +21 -0
  271. pylzt-0.1.0/src/pylzt/models/market/item_stickers.py +20 -0
  272. pylzt-0.1.0/src/pylzt/models/market/item_telegram_group_counters.py +20 -0
  273. pylzt-0.1.0/src/pylzt/models/market/item_uplay_game.py +23 -0
  274. pylzt-0.1.0/src/pylzt/models/market/item_valorant_inventory.py +19 -0
  275. pylzt-0.1.0/src/pylzt/models/market/item_wf_server.py +19 -0
  276. pylzt-0.1.0/src/pylzt/models/market/letter.py +22 -0
  277. pylzt-0.1.0/src/pylzt/models/market/list_user_item.py +100 -0
  278. pylzt-0.1.0/src/pylzt/models/market/list_user_response.py +49 -0
  279. pylzt-0.1.0/src/pylzt/models/market/list_viewed_response.py +28 -0
  280. pylzt-0.1.0/src/pylzt/models/market/llm_item.py +101 -0
  281. pylzt-0.1.0/src/pylzt/models/market/login_data.py +24 -0
  282. pylzt-0.1.0/src/pylzt/models/market/ma_file.py +28 -0
  283. pylzt-0.1.0/src/pylzt/models/market/ma_file_session.py +21 -0
  284. pylzt-0.1.0/src/pylzt/models/market/managing_bulk_action_response.py +19 -0
  285. pylzt-0.1.0/src/pylzt/models/market/managing_bulk_get_item.py +20 -0
  286. pylzt-0.1.0/src/pylzt/models/market/managing_bulk_get_response.py +19 -0
  287. pylzt-0.1.0/src/pylzt/models/market/managing_change_password_response.py +18 -0
  288. pylzt-0.1.0/src/pylzt/models/market/managing_steam_inventory_value_data.py +30 -0
  289. pylzt-0.1.0/src/pylzt/models/market/managing_steam_inventory_value_item.py +28 -0
  290. pylzt-0.1.0/src/pylzt/models/market/managing_telegram_code_response.py +20 -0
  291. pylzt-0.1.0/src/pylzt/models/market/managing_temp_email_password_item.py +17 -0
  292. pylzt-0.1.0/src/pylzt/models/market/market_status_message_response.py +17 -0
  293. pylzt-0.1.0/src/pylzt/models/market/minecraft_item.py +112 -0
  294. pylzt-0.1.0/src/pylzt/models/market/payments_currency_response.py +20 -0
  295. pylzt-0.1.0/src/pylzt/models/market/payments_fee_response.py +20 -0
  296. pylzt-0.1.0/src/pylzt/models/market/payments_invoice_list_response.py +21 -0
  297. pylzt-0.1.0/src/pylzt/models/market/profile_claims_response.py +20 -0
  298. pylzt-0.1.0/src/pylzt/models/market/profile_get_user.py +93 -0
  299. pylzt-0.1.0/src/pylzt/models/market/providers_bep20.py +18 -0
  300. pylzt-0.1.0/src/pylzt/models/market/proxy.py +18 -0
  301. pylzt-0.1.0/src/pylzt/models/market/proxy_proxy.py +23 -0
  302. pylzt-0.1.0/src/pylzt/models/market/publishing_check_item.py +101 -0
  303. pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_buyer.py +24 -0
  304. pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_guarantee.py +26 -0
  305. pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_seller.py +27 -0
  306. pylzt-0.1.0/src/pylzt/models/market/publishing_fast_sell_response.py +19 -0
  307. pylzt-0.1.0/src/pylzt/models/market/purchasing_check_item.py +107 -0
  308. pylzt-0.1.0/src/pylzt/models/market/purchasing_check_item_seller.py +27 -0
  309. pylzt-0.1.0/src/pylzt/models/market/purchasing_check_response.py +19 -0
  310. pylzt-0.1.0/src/pylzt/models/market/purchasing_confirm_response.py +20 -0
  311. pylzt-0.1.0/src/pylzt/models/market/query_data_app_id_response.py +22 -0
  312. pylzt-0.1.0/src/pylzt/models/market/rendered_avatars.py +19 -0
  313. pylzt-0.1.0/src/pylzt/models/market/rendered_backgrounds.py +18 -0
  314. pylzt-0.1.0/src/pylzt/models/market/riot_item.py +146 -0
  315. pylzt-0.1.0/src/pylzt/models/market/roblox_item.py +113 -0
  316. pylzt-0.1.0/src/pylzt/models/market/social_club_item.py +118 -0
  317. pylzt-0.1.0/src/pylzt/models/market/stats.py +19 -0
  318. pylzt-0.1.0/src/pylzt/models/market/stats_market.py +20 -0
  319. pylzt-0.1.0/src/pylzt/models/market/status_item_response.py +19 -0
  320. pylzt-0.1.0/src/pylzt/models/market/steam_item.py +204 -0
  321. pylzt-0.1.0/src/pylzt/models/market/supercell_item.py +123 -0
  322. pylzt-0.1.0/src/pylzt/models/market/system.py +33 -0
  323. pylzt-0.1.0/src/pylzt/models/market/system_providers.py +31 -0
  324. pylzt-0.1.0/src/pylzt/models/market/tag.py +21 -0
  325. pylzt-0.1.0/src/pylzt/models/market/telegram_item.py +98 -0
  326. pylzt-0.1.0/src/pylzt/models/market/tik_tok_item.py +106 -0
  327. pylzt-0.1.0/src/pylzt/models/market/uplay_item.py +127 -0
  328. pylzt-0.1.0/src/pylzt/models/market/user.py +22 -0
  329. pylzt-0.1.0/src/pylzt/models/market/user_balance.py +25 -0
  330. pylzt-0.1.0/src/pylzt/models/market/user_custom_fields.py +38 -0
  331. pylzt-0.1.0/src/pylzt/models/market/user_dob.py +19 -0
  332. pylzt-0.1.0/src/pylzt/models/market/user_domain_zone.py +20 -0
  333. pylzt-0.1.0/src/pylzt/models/market/user_item_states.py +31 -0
  334. pylzt-0.1.0/src/pylzt/models/market/user_item_states_discount_request.py +19 -0
  335. pylzt-0.1.0/src/pylzt/models/market/user_item_states_stickied.py +19 -0
  336. pylzt-0.1.0/src/pylzt/models/market/user_rendered.py +21 -0
  337. pylzt-0.1.0/src/pylzt/models/market/user_telegram_client.py +24 -0
  338. pylzt-0.1.0/src/pylzt/models/market/vpn_item.py +85 -0
  339. pylzt-0.1.0/src/pylzt/models/market/warface_item.py +97 -0
  340. pylzt-0.1.0/src/pylzt/models/notification.py +42 -0
  341. pylzt-0.1.0/src/pylzt/models/payment.py +100 -0
  342. pylzt-0.1.0/src/pylzt/models/profile.py +27 -0
  343. pylzt-0.1.0/src/pylzt/pagination.py +64 -0
  344. pylzt-0.1.0/src/pylzt/plugins.py +46 -0
  345. pylzt-0.1.0/src/pylzt/proxy_pool/__init__.py +0 -0
  346. pylzt-0.1.0/src/pylzt/proxy_pool/base.py +75 -0
  347. pylzt-0.1.0/src/pylzt/proxy_pool/health.py +78 -0
  348. pylzt-0.1.0/src/pylzt/proxy_pool/round_robin.py +77 -0
  349. pylzt-0.1.0/src/pylzt/proxy_pool/source.py +93 -0
  350. pylzt-0.1.0/src/pylzt/proxy_pool/sticky.py +109 -0
  351. pylzt-0.1.0/src/pylzt/py.typed +0 -0
  352. pylzt-0.1.0/src/pylzt/storage/__init__.py +17 -0
  353. pylzt-0.1.0/src/pylzt/storage/batch.py +100 -0
  354. pylzt-0.1.0/src/pylzt/storage/cursor.py +54 -0
  355. pylzt-0.1.0/src/pylzt/sync/__init__.py +5 -0
  356. pylzt-0.1.0/src/pylzt/sync/client.py +46 -0
  357. pylzt-0.1.0/src/pylzt/sync/runner.py +73 -0
  358. pylzt-0.1.0/src/pylzt/token_pool/__init__.py +1 -0
  359. pylzt-0.1.0/src/pylzt/token_pool/_static.py +68 -0
  360. pylzt-0.1.0/src/pylzt/token_pool/base.py +54 -0
  361. pylzt-0.1.0/src/pylzt/token_pool/bucket.py +113 -0
  362. pylzt-0.1.0/src/pylzt/token_pool/governor.py +101 -0
  363. pylzt-0.1.0/src/pylzt/token_pool/rate_limit.py +46 -0
  364. pylzt-0.1.0/src/pylzt/token_pool/round_robin.py +115 -0
  365. pylzt-0.1.0/src/pylzt/token_pool/selector.py +42 -0
  366. pylzt-0.1.0/src/pylzt/transport/__init__.py +1 -0
  367. pylzt-0.1.0/src/pylzt/transport/base.py +163 -0
  368. pylzt-0.1.0/src/pylzt/transport/middleware.py +127 -0
  369. pylzt-0.1.0/src/pylzt/transport/session.py +162 -0
  370. pylzt-0.1.0/src/pylzt/types.py +179 -0
  371. pylzt-0.1.0/tests/dev_codegen/test_diff.py +95 -0
  372. pylzt-0.1.0/tests/dev_codegen/test_pipeline.py +59 -0
  373. pylzt-0.1.0/tests/pylzt/contracts/test_cache_contract.py +34 -0
  374. pylzt-0.1.0/tests/pylzt/contracts/test_transport_contract.py +111 -0
  375. pylzt-0.1.0/tests/pylzt/e2e/test_live_read.py +293 -0
  376. pylzt-0.1.0/tests/pylzt/test_batch.py +290 -0
  377. pylzt-0.1.0/tests/pylzt/test_bound_model.py +117 -0
  378. pylzt-0.1.0/tests/pylzt/test_cache.py +86 -0
  379. pylzt-0.1.0/tests/pylzt/test_client_batching.py +154 -0
  380. pylzt-0.1.0/tests/pylzt/test_client_loop.py +129 -0
  381. pylzt-0.1.0/tests/pylzt/test_client_plugin_discovery.py +113 -0
  382. pylzt-0.1.0/tests/pylzt/test_client_reconfigure.py +67 -0
  383. pylzt-0.1.0/tests/pylzt/test_client_request.py +41 -0
  384. pylzt-0.1.0/tests/pylzt/test_concurrency.py +118 -0
  385. pylzt-0.1.0/tests/pylzt/test_cursor_storage.py +44 -0
  386. pylzt-0.1.0/tests/pylzt/test_error_registry.py +96 -0
  387. pylzt-0.1.0/tests/pylzt/test_governor.py +68 -0
  388. pylzt-0.1.0/tests/pylzt/test_media.py +253 -0
  389. pylzt-0.1.0/tests/pylzt/test_method_as_class.py +66 -0
  390. pylzt-0.1.0/tests/pylzt/test_methods_declarative.py +145 -0
  391. pylzt-0.1.0/tests/pylzt/test_namespaces.py +115 -0
  392. pylzt-0.1.0/tests/pylzt/test_pagination.py +60 -0
  393. pylzt-0.1.0/tests/pylzt/test_parse.py +92 -0
  394. pylzt-0.1.0/tests/pylzt/test_plugins.py +112 -0
  395. pylzt-0.1.0/tests/pylzt/test_proxy_pool.py +253 -0
  396. pylzt-0.1.0/tests/pylzt/test_rate_limited_governor.py +123 -0
  397. pylzt-0.1.0/tests/pylzt/test_resumable_exporter.py +68 -0
  398. pylzt-0.1.0/tests/pylzt/test_session_middleware.py +101 -0
  399. pylzt-0.1.0/tests/pylzt/test_sync.py +105 -0
  400. pylzt-0.1.0/tests/pylzt/test_token_pool.py +222 -0
  401. pylzt-0.1.0/tests/test_entry_helpers.py +72 -0
  402. pylzt-0.1.0/uv.lock +597 -0
@@ -0,0 +1 @@
1
+ .githooks/* text eol=lf
@@ -0,0 +1,18 @@
1
+ #!/bin/sh
2
+ # Mirrors .github/workflows/ci.yml — GitHub Actions is unusable on this
3
+ # account (locked pending a payment method), so this is the actual CI gate.
4
+ set -e
5
+
6
+ echo "[pre-push] ruff check..."
7
+ uv run ruff check src tests
8
+
9
+ echo "[pre-push] ruff format --check..."
10
+ uv run ruff format --check src tests
11
+
12
+ echo "[pre-push] mypy..."
13
+ uv run mypy
14
+
15
+ echo "[pre-push] pytest (not e2e)..."
16
+ uv run pytest -q
17
+
18
+ echo "[pre-push] all checks passed"
@@ -0,0 +1,41 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.12"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v3
21
+ with:
22
+ enable-cache: true
23
+
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Sync deps
29
+ run: uv sync --extra dev
30
+
31
+ - name: Lint (ruff check)
32
+ run: uv run ruff check src tests
33
+
34
+ - name: Format check (ruff format)
35
+ run: uv run ruff format --check src tests
36
+
37
+ - name: Type check (mypy --strict)
38
+ run: uv run mypy
39
+
40
+ - name: Test (pytest)
41
+ run: uv run pytest -q
@@ -0,0 +1,94 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v3
18
+ with:
19
+ enable-cache: true
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Sync deps
26
+ run: uv sync --extra dev
27
+
28
+ - name: Lint
29
+ run: uv run ruff check src tests
30
+
31
+ - name: Type check
32
+ run: uv run mypy
33
+
34
+ - name: Test
35
+ run: uv run pytest -q
36
+
37
+ - name: Build sdist + wheel
38
+ run: uv build
39
+
40
+ - uses: actions/upload-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+
45
+ publish:
46
+ runs-on: ubuntu-latest
47
+ needs: build
48
+ environment:
49
+ name: pypi
50
+ url: https://pypi.org/project/pylzt/
51
+ permissions:
52
+ id-token: write # OIDC trusted publishing — no PyPI token stored in secrets
53
+ steps:
54
+ - uses: actions/download-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
58
+
59
+ - name: Install uv
60
+ uses: astral-sh/setup-uv@v3
61
+
62
+ - name: Publish to PyPI
63
+ run: uv publish
64
+
65
+ release-notes:
66
+ runs-on: ubuntu-latest
67
+ needs: publish
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+ with: { fetch-depth: 0 }
71
+
72
+ - id: notes
73
+ run: |
74
+ TAG="${GITHUB_REF#refs/tags/}"
75
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
76
+ PREV="$(git tag --sort=-creatordate | grep -v "^$TAG$" | head -n1 || true)"
77
+ {
78
+ echo "notes<<EOF"
79
+ if [[ -n "$PREV" ]]; then
80
+ echo "### Changes since $PREV"
81
+ git --no-pager log --pretty=format:'- %s (%h)' "$PREV..$TAG"
82
+ else
83
+ echo "### First tagged release"
84
+ fi
85
+ echo "EOF"
86
+ } >> "$GITHUB_OUTPUT"
87
+
88
+ - uses: softprops/action-gh-release@v2
89
+ with:
90
+ tag_name: ${{ steps.notes.outputs.tag }}
91
+ name: ${{ steps.notes.outputs.tag }}
92
+ body: ${{ steps.notes.outputs.notes }}
93
+ draft: false
94
+ prerelease: ${{ contains(steps.notes.outputs.tag, '-rc') || contains(steps.notes.outputs.tag, '-alpha') || contains(steps.notes.outputs.tag, '-beta') }}
pylzt-0.1.0/.gitignore ADDED
@@ -0,0 +1,38 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ venv/
6
+ env/
7
+
8
+ # Env / secrets
9
+ *.local
10
+
11
+ # Auto-generated module docs — regenerate via docskill, never versioned
12
+ **/_MODULE_AUTO.md
13
+
14
+ # Scraped OpenAPI page cache + scrape logs — regenerate via dev/, never versioned.
15
+ # The merged schema JSONs themselves ARE versioned (exceptions below) so a clone can
16
+ # `python -m dev.codegen build` without re-scraping readme.io first.
17
+ dev/generated/*
18
+ !dev/generated/openapi/
19
+ dev/generated/openapi/*
20
+ !dev/generated/openapi/lzt_market.json
21
+ !dev/generated/openapi/lzt_forum.json
22
+ !dev/generated/openapi/lzt_antipublic.json
23
+
24
+ # codegen staging tree (regenerated by `python -m dev.codegen generate`)
25
+ dev/codegen/generated/
26
+
27
+ # ad-hoc probe/scratch output dumped while investigating — never versioned
28
+ **/_probe_out*.txt
29
+
30
+ # Ignore every dotfile/dotdir by default (IDE state, OS cruft, caches, .env, .venv, ...) —
31
+ # except the ones we actually track. Add a new `!.foo` line here whenever a dotfile
32
+ # needs to be committed, or it silently won't stage.
33
+ .*
34
+ !.gitattributes
35
+ !.gitignore
36
+ !.github/
37
+ !.githooks/
38
+ !.pre-commit-config.yaml
@@ -0,0 +1,32 @@
1
+ # Local dev gate — aborts `git commit` / `git push` when checks fail, before anything leaves the
2
+ # machine. CI (GitHub Actions) stays the authoritative server-side gate; this is the fast local one.
3
+ # One-time per clone: uv run pre-commit install --hook-type pre-commit --hook-type pre-push
4
+ # Bypass in a pinch: git commit/push --no-verify
5
+ repos:
6
+ - repo: local
7
+ hooks:
8
+ - id: ruff-check
9
+ name: ruff check
10
+ entry: uv run ruff check --fix
11
+ language: system
12
+ types: [python]
13
+ require_serial: true
14
+ - id: ruff-format
15
+ name: ruff format
16
+ entry: uv run ruff format
17
+ language: system
18
+ types: [python]
19
+ require_serial: true
20
+ # mypy + pytest are heavier — run them on push, not on every commit.
21
+ - id: mypy
22
+ name: mypy (strict)
23
+ entry: uv run mypy
24
+ language: system
25
+ pass_filenames: false
26
+ stages: [pre-push]
27
+ - id: pytest
28
+ name: pytest
29
+ entry: uv run pytest -q
30
+ language: system
31
+ pass_filenames: false
32
+ stages: [pre-push]
pylzt-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zlexdev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pylzt-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,344 @@
1
+ Metadata-Version: 2.4
2
+ Name: pylzt
3
+ Version: 0.1.0
4
+ Summary: Typed async SDK over the lzt.market / lolzteam API — token-pooled, rate-limited, proxy-aware, generated from the official OpenAPI spec.
5
+ Project-URL: Homepage, https://github.com/open-lzt/pylzt
6
+ Project-URL: Repository, https://github.com/open-lzt/pylzt
7
+ Author: pylzt contributors
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: async,httpx,lolzteam,lzt,marketplace,sdk
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: httpx[socks]>=0.27
13
+ Requires-Dist: pydantic>=2.7
14
+ Requires-Dist: structlog>=24.1
15
+ Provides-Extra: dev
16
+ Requires-Dist: mypy>=1.10; extra == 'dev'
17
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
18
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
19
+ Requires-Dist: pytest>=8.2; extra == 'dev'
20
+ Requires-Dist: ruff>=0.5; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ <p align="right"><a href="README.en.md">English</a> · <b>Русский</b></p>
24
+
25
+ <div align="center">
26
+
27
+ # pylzt
28
+
29
+ <sub>Типизированный async-фреймворк над API lzt.market / lolzteam / AntiPublic — не тонкая HTTP-обёртка</sub>
30
+
31
+ [![CI](https://github.com/open-lzt/pylzt/actions/workflows/ci.yml/badge.svg)](https://github.com/open-lzt/pylzt/actions/workflows/ci.yml)
32
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/)
33
+ [![Pydantic v2](https://img.shields.io/badge/pydantic-v2-e92063)](https://docs.pydantic.dev/)
34
+ [![mypy: strict](https://img.shields.io/badge/mypy-strict-2a6db2)](https://mypy-lang.org/)
35
+ [![Ruff](https://img.shields.io/badge/lint-ruff-d7ff64)](https://docs.astral.sh/ruff/)
36
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
37
+
38
+ </div>
39
+
40
+ [Полная документация](docs/) · [Документация для AI-агентов](docs/for_ai/)
41
+
42
+ Типизированный async-**фреймворк** над API маркетплейса [lzt.market](https://lzt.market),
43
+ API форума [lolzteam](https://lolz.live) и API проверки утечек [AntiPublic](https://antipublic.one) —
44
+ не тонкая HTTP-обёртка.
45
+
46
+ **[Зачем фреймворк](#зачем-фреймворк-а-не-библиотека)** ·
47
+ **[Быстрый старт](#быстрый-старт)** ·
48
+ **[Sync](#sync-без-await)** ·
49
+ **[Мок](#против-мока-lzt-testnet)** ·
50
+ **[Пагинация](#пагинация)** ·
51
+ **[Батчинг](#батчинг-n-вызовов-в-один-запрос)** ·
52
+ **[Загрузка медиа](#загрузка-медиа)** ·
53
+ **[AntiPublic](#antipublic-api-проверки-утечек)** ·
54
+ **[Ошибки](#обработка-ошибок)** ·
55
+ **[Кодоген](#кодоген-билдер)**
56
+
57
+ ## Зачем фреймворк, а не библиотека
58
+
59
+ Обёртка даёт типизированные методы поверх HTTP-клиента. pylzt поставляет саму
60
+ эксплуатационную машинерию, которая нужна продовой интеграции, — уже собранную и подключённую:
61
+
62
+ - **Пул токенов** (`token_pool/round_robin.py`) — round-robin по множеству токенов
63
+ маркетплейса, каждый учитывается собственным бакетом на `RateClass` по официально
64
+ опубликованным лимитам (Market 120/мин общий + 20/мин Category Search; Forum 300/мин).
65
+ У AntiPublic свой пул с одним ключом (`token_pool/_static.py`) — лицензионный ключ
66
+ не взаимозаменяем с OAuth-токеном, поэтому в общую ротацию он не попадает.
67
+ - **Пул прокси** (`proxy_pool/`) — sticky-per-token или round-robin egress-прокси
68
+ (HTTP/HTTPS/SOCKS5) с отслеживанием здоровья через circuit-breaker на каждый прокси.
69
+ - **Отказоустойчивость** (`transport/base.py`, `lib/retry.py`) — повторы с джиттером
70
+ backoff'а, уважающие `Retry-After`, типизированная само-регистрирующаяся иерархия
71
+ ошибок (`errors.py`), схлопывающий запросы в один `/batch` (`lib/batch.py`), TTL-кэш,
72
+ уважающий серверный `cacheTTL`.
73
+ - **Method-as-class** (`methods/base.py`) — каждый эндпоинт — это frozen Pydantic-модель
74
+ `BaseMethod[T]`, а не вручную поддерживаемая функция: некорректные поля запроса
75
+ падают на этапе конструирования, а не на проводе; `Client.execute(method)` — единственный
76
+ путь выполнения запроса, к которому делегируют все доменные namespace'ы и все
77
+ сгенерированные методы фасада.
78
+ - **Сгенерированный, а не переписанный вручную** (`dev/codegen/`) — методы, модели ответов,
79
+ enum'ы и фасады генерируются из официального OpenAPI-референса и устанавливаются
80
+ **плоско** в библиотеку за ruff+mypy-гейтом. Поля `format: binary` автоматически
81
+ распознаются в реальный тип `Media`, поэтому эндпоинты загрузки файлов получают
82
+ типизированную поддержку multipart бесплатно.
83
+ - **Sync и async на одном движке** (`sync/runner.py`) — `SyncClient` не является второй
84
+ реализацией рейт-лимитинга и повторов; он запускает *тот же* async-движок в фоновом
85
+ потоке с event loop'ом (`SyncRunner`), причём тип возврата каждого метода совпадает
86
+ с развёрнутым типом его async-аналога под `mypy --strict`.
87
+
88
+ ## Быстрый старт
89
+
90
+ ```bash
91
+ pip install "git+https://github.com/open-lzt/pylzt.git"
92
+ ```
93
+
94
+ ```python
95
+ import asyncio
96
+
97
+ from pylzt import Client
98
+ from pylzt.types import Category
99
+
100
+
101
+ async def main() -> None:
102
+ async with Client.from_token("<market-token>") as client: # или Client.from_env() из $LZT_TOKEN
103
+ lot = await client.market.get_lot(item_id=42)
104
+ print(lot.item_id, lot.price, lot.title)
105
+
106
+ async for lot in client.market.list_lots(category=Category.STEAM):
107
+ print(lot.item_id, lot.price)
108
+
109
+
110
+ asyncio.run(main())
111
+ ```
112
+
113
+ `client.market` / `client.forum` / `client.antipublic` — это три доменных namespace'а:
114
+ каждый эндпоинт из официальной спецификации — реальный метод на соответствующем
115
+ из них (`client.forum.threads_get(...)`, `client.antipublic.license_check_license()`).
116
+
117
+ ## Sync без `await`
118
+
119
+ ```python
120
+ from pylzt.sync.client import SyncClient
121
+
122
+ with SyncClient("<market-token>") as client:
123
+ lot = client.market.get_lot(item_id=42)
124
+ ```
125
+
126
+ ## Против мока (lzt-testnet)
127
+
128
+ ```python
129
+ from pylzt import Client, ClientConfig
130
+
131
+ async with Client.from_token("t", config=ClientConfig.for_testnet()) as client:
132
+ ... # всё бьётся в локальный мок 127.0.0.1:8765
133
+ ```
134
+
135
+ ## Пагинация
136
+
137
+ ```python
138
+ from decimal import Decimal
139
+ from pylzt.types import Category, OrderBy
140
+
141
+ # стрим по страницам (max_pages — необязательный предел)
142
+ async for lot in client.market.list_lots(category=Category.STEAM, order_by=OrderBy.PRICE_ASC, max_pages=5):
143
+ ...
144
+
145
+ all_lots = await client.market.list_lots(category=Category.STEAM, pmax=Decimal("500")).collect(limit=200)
146
+ first = await client.market.list_lots(category=Category.STEAM).first_page()
147
+ ```
148
+
149
+ ## Батчинг N вызовов в один запрос
150
+
151
+ Три способа — выбирай по тому, как вызовы возникают в твоём коде:
152
+
153
+ ```python
154
+ from pylzt.methods.catalog import GetLot
155
+ from pylzt.methods.categories import CategoryParams
156
+ from pylzt.types import Category, ItemId
157
+
158
+ # 1. Список уже собран заранее — один POST /batch, один вызов.
159
+ results = await client.execute_batch([
160
+ GetLot(item_id=ItemId(1)),
161
+ CategoryParams(category=Category.STEAM),
162
+ ])
163
+
164
+ # 2. Вызовы разбросаны по функции/циклу — оборачиваем регион, каждый execute()
165
+ # внутри схлопывается в /batch-запросы вместо отправки по одному.
166
+ async with client.batching():
167
+ lot, categories = await asyncio.gather(
168
+ client.execute(GetLot(item_id=ItemId(1))),
169
+ client.execute(CategoryParams(category=Category.STEAM)),
170
+ )
171
+
172
+ # 3. Оборачивать нечего (например, вызовы возникают в несвязанных местах кода) — job()
173
+ # схлопывается с любым другим одновременным вызовом job() через общий,
174
+ # живущий весь клиент коллектор.
175
+ lot = await client.job(GetLot(item_id=ItemId(1)))
176
+ ```
177
+
178
+ ## Загрузка медиа
179
+
180
+ ```python
181
+ from pylzt import Media
182
+
183
+ avatar = Media.from_path("avatar.png")
184
+ await client.forum.users_avatar_upload(user_id="me", avatar=avatar)
185
+ ```
186
+
187
+ Про `media_storage=` (опциональный кэш байтов после загрузки) — см.
188
+ [`docs/integration-guide.md`](docs/integration-guide.md).
189
+
190
+ ## AntiPublic (API проверки утечек)
191
+
192
+ Отдельный лицензионный ключ, не токен market/forum — он никогда не попадает в ту же
193
+ ротацию (см. обзор фреймворка выше):
194
+
195
+ ```python
196
+ async with Client.from_token("<market-token>", antipublic_key="<antipublic-license-key>") as client:
197
+ remaining = await client.antipublic.license_available_queries()
198
+ hit = await client.antipublic.license_check_lines(lines=("user:pass",))
199
+ ```
200
+
201
+ Вызов `client.antipublic.*` без `antipublic_key=` бросает `CredentialMissing` —
202
+ громкий отказ вместо тихого no-op.
203
+
204
+ ## Обработка ошибок
205
+
206
+ Каждая ошибка, которую бросает SDK, — подкласс `LztError`: ловите конкретный тип,
207
+ из которого можете восстановиться, остальное пусть летит дальше:
208
+
209
+ ```python
210
+ from pylzt import AuthFailed, NotFound, RateLimited, TransportError
211
+ from pylzt.types import ItemId
212
+
213
+ try:
214
+ lot = await client.market.get_lot(item_id=ItemId(999_999_999))
215
+ except NotFound:
216
+ ... # лот не существует или не виден этому токену
217
+ except RateLimited as exc:
218
+ ... # exc несёт retry_after — пул токенов уже сам делает бэкофф
219
+ except AuthFailed:
220
+ ... # токен мёртв/отозван — выведите его из ротации, см. reconfigure()
221
+ except TransportError:
222
+ ... # 5xx апстрима после исчерпания повторов
223
+ ```
224
+
225
+ Полный обзор — DI, конфиг, фейки для тестов, `reconfigure()` для живой ротации
226
+ токенов, полная таблица ошибок: **[`docs/integration-guide.md`](docs/integration-guide.md)**.
227
+
228
+ ## Кодоген (билдер)
229
+
230
+ Методы SDK, модели ответов, enum'ы и фасады генерируются из официального
231
+ OpenAPI-референса на readme.io и устанавливаются **плоско** в библиотеку за
232
+ ruff + mypy-гейтом. `dev/codegen/` (`pipeline.py` + `generator.py` + `scraper.py`,
233
+ запускается через `python -m dev.codegen`) двухфазный: `generate` рендерит во
234
+ временное дерево и никогда не трогает библиотеку; `install` продвигает staging
235
+ в `src/pylzt/` за гейтом и откатывается при любом сбое — библиотека на диске
236
+ никогда не остаётся сломанной регеном.
237
+
238
+ ### Команды
239
+
240
+ ```bash
241
+ python -m dev.codegen generate # рендер только в dev/codegen/generated/
242
+ python -m dev.codegen install # продвинуть staging -> библиотеку, за гейтом
243
+ python -m dev.codegen build # generate + install за один проход (частый случай)
244
+ python -m dev.codegen build --scrape # сначала пере-скрейпить OpenAPI-спеку, потом build
245
+ python -m dev.codegen scrape # только скрейп + слияние спеки, без кодогена
246
+ python -m dev.codegen check # запустить ruff + mypy + import-гейт, без регена
247
+ ```
248
+
249
+ Полезные флаги (повторяемые, свободно комбинируются):
250
+
251
+ | Флаг | На каких командах | Эффект |
252
+ |---|---|---|
253
+ | `--api market` / `--api forum` / `--api antipublic` | `generate`, `build` | ограничить одним API (повторяемо); по умолчанию — все три |
254
+ | `--scrape` | `generate`, `build` | пере-скачать референс readme.io перед рендером |
255
+ | `--refresh` | `generate --scrape`, `build --scrape`, `scrape` | игнорировать дисковый кэш страниц, перекачать каждую страницу |
256
+ | `--model-backend {pydantic,dataclass}` | `generate`, `build` | цель для response-DTO; по умолчанию `pydantic` (методы запросов всегда frozen Pydantic-модели) |
257
+ | `--no-validate` | `install`, `build` | пропустить ruff+mypy-гейт при установке (опасно — только для быстрого локального взгляда на staged-вывод) |
258
+ | `--site market` / `--site forum` / `--site antipublic` | `scrape` | ограничить скрейпинг одним сайтом (повторяемо) |
259
+
260
+ ### Что делает каждая фаза
261
+
262
+ - **`scraper.py`** скачивает каждую referen-страницу readme.io для сайта и объединяет
263
+ вложенные фрагменты OpenAPI 3.1 в одну слитую спеку, кэшируя каждую страницу на диске
264
+ под `dev/generated/openapi/.page_cache/<site>/` (`--refresh` обходит кэш). Слитая спека
265
+ пишется в `dev/generated/openapi/lzt_<site>.json` — **эти JSON-файлы версионируются**
266
+ (см. ниже); кэш страниц и логи скрейпа рядом с ними — нет.
267
+ - **`generator.py`** превращает эту спеку в типизированные method-классы (`BaseMethod[T]`),
268
+ вложенные Pydantic-модели ответов, `StrEnum`, async-методы фасада и параллельный
269
+ **sync**-фасад на каждый сайт (`facades/sync_{api}.py` — каждый метод — тонкая блокирующая
270
+ обёртка над своим async-аналогом через `SyncRunner`, без второй реализации,
271
+ выведенной из спеки) — плоско в `dev/codegen/generated/{methods,models,enums,facades}/`.
272
+ Также прогоняет проход нормализации над сырой экстракцией, чтобы вывод оставался
273
+ качества "написан вручную", а не буквальным дампом 1:1 из спеки — сворачивая
274
+ структурно-идентичные модели в один класс, поднимая общие generic-базы, отображая
275
+ поля запроса `format: binary` в реальный тип `Media`, и **переиспользуя написанные
276
+ вручную примитивы вместо их дублирования**: любой enum, у которого значения на
277
+ проводе — `{yes, no, nomatter}` (или подмножество), схлопывается на единственный
278
+ `pylzt.types.Tristate` — с classmethod'ом `Tristate.from_bool(value: bool | None)` —
279
+ вместо дублирующего класса той же формы на каждое имя поля (`Tel`, `EditBtag`,
280
+ `ClashPass`, ...); любая модель ответа, у которой ведущее поле — `status: str`,
281
+ переезжает на `pylzt.models.base.BaseResponse`, которому принадлежит `is_ok()`,
282
+ вместо того чтобы каждая модель носила свою копию этого поля. `EXISTING_TYPES_ENUMS`
283
+ в `generator.py` — полный список написанных вручную enum'ов, которые кодоген
284
+ импортирует, а не регенерирует.
285
+ - **`pipeline.py`** снимает снапшот текущих установленных сгенерированных файлов,
286
+ стирает их (чтобы файл удалённого домена исчезал на следующем build'е), копирует
287
+ staged-набор внутрь, запускает `ruff --fix`, затем ruff+mypy+import-гейт, и
288
+ восстанавливает снапшот при любом сбое.
289
+
290
+ Сгенерированные и написанные вручную модули сосуществуют плоско в одном пакете —
291
+ сгенерированные несут маркер авто-заголовка и имя с префиксом `{api}_` / `{api}`,
292
+ написанные вручную — без префикса, и `install` отказывается перезаписывать
293
+ написанный вручную модуль (`_guard_no_clobber`). Полный контракт — в
294
+ `dev/codegen/_MODULE.md`.
295
+
296
+ ### Схема API
297
+
298
+ `dev/generated/openapi/lzt_market.json`, `lzt_forum.json` и `lzt_antipublic.json` —
299
+ слитые OpenAPI-спеки, которые производит `scraper.py`, — закоммичены, чтобы клон
300
+ мог выполнить `python -m dev.codegen build` без пере-скрейпа readme.io. Всё остальное
301
+ под `dev/generated/` (кэш страниц, логи скрейпа и staging-дерево
302
+ `dev/codegen/generated/`) остаётся в gitignore и пересобирается по требованию.
303
+ Пере-скрейпить с `python -m dev.codegen scrape --refresh`, когда апстрим-референс
304
+ меняется, и закоммитить обновлённые JSON-файлы вместе с диффом кодогена, который они
305
+ производят.
306
+
307
+ ### Живая верификация
308
+
309
+ Каждый сгенерированный файл несёт докстринг `Generated by forge — DO NOT EDIT` —
310
+ заявленные в спеке типы не всегда совпадают с тем, что реально возвращает API, поэтому
311
+ свежий реген — никогда не место для ручного патча. `tests/pylzt/e2e/test_live_read.py`
312
+ (маркер `e2e`, нужен `LZT_E2E_TOKEN`, исключён из запуска по умолчанию) автоматически
313
+ находит и прогоняет каждый GET-эндпоинт без аргументов против реального API. Что уже
314
+ проверено, что всё ещё известно как сломанное, и механизм ручного патча для починки
315
+ расхождения спеки и реальности без того, чтобы следующий прогон кодогена тихо его
316
+ откатил — см. **`docs/codegen-runbook.md`**.
317
+
318
+ ## Разработка
319
+
320
+ GitHub Actions недоступен на этом аккаунте (заблокирован до подключения способа
321
+ оплаты), поэтому `.github/workflows/ci.yml` сегодня не является рабочим гейтом.
322
+ `.githooks/pre-push` зеркалит его локально (ruff check, ruff format --check, mypy,
323
+ pytest) и блокирует push при сбое. После клонирования один раз укажите git на него:
324
+ `git config core.hooksPath .githooks`.
325
+
326
+ ## Контрибьютинг
327
+
328
+ ```bash
329
+ git clone https://github.com/open-lzt/pylzt && cd pylzt
330
+ uv sync --extra dev
331
+ git config core.hooksPath .githooks # локальный ruff+mypy+pytest-гейт на push, см. выше
332
+ uv run pytest -q
333
+ ```
334
+
335
+ PR идут против `main`. `.githooks/pre-push` — актуальный гейт прямо сейчас (см.
336
+ "Разработка" выше) — он должен пройти до того, как push пройдёт.
337
+
338
+ ## Авторы
339
+
340
+ - [zlexdev](https://github.com/zlexdev)
341
+
342
+ ## Лицензия
343
+
344
+ [MIT](LICENSE).