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.
- pylzt-0.1.0/.gitattributes +1 -0
- pylzt-0.1.0/.githooks/pre-push +18 -0
- pylzt-0.1.0/.github/workflows/ci.yml +41 -0
- pylzt-0.1.0/.github/workflows/release.yml +94 -0
- pylzt-0.1.0/.gitignore +38 -0
- pylzt-0.1.0/.pre-commit-config.yaml +32 -0
- pylzt-0.1.0/LICENSE +21 -0
- pylzt-0.1.0/PKG-INFO +344 -0
- pylzt-0.1.0/README.en.md +312 -0
- pylzt-0.1.0/README.md +322 -0
- pylzt-0.1.0/dev/codegen/_MODULE.md +94 -0
- pylzt-0.1.0/dev/codegen/__init__.py +12 -0
- pylzt-0.1.0/dev/codegen/__main__.py +116 -0
- pylzt-0.1.0/dev/codegen/diff.py +143 -0
- pylzt-0.1.0/dev/codegen/generator.py +1670 -0
- pylzt-0.1.0/dev/codegen/pipeline.py +281 -0
- pylzt-0.1.0/dev/codegen/scraper.py +202 -0
- pylzt-0.1.0/dev/generated/openapi/lzt_antipublic.json +828 -0
- pylzt-0.1.0/dev/generated/openapi/lzt_forum.json +15215 -0
- pylzt-0.1.0/dev/generated/openapi/lzt_market.json +51839 -0
- pylzt-0.1.0/dist/.gitignore +1 -0
- pylzt-0.1.0/docs/codegen-runbook.en.md +225 -0
- pylzt-0.1.0/docs/codegen-runbook.md +276 -0
- pylzt-0.1.0/docs/for_ai/index.en.md +49 -0
- pylzt-0.1.0/docs/for_ai/index.md +60 -0
- pylzt-0.1.0/docs/integration-guide.en.md +366 -0
- pylzt-0.1.0/docs/integration-guide.md +367 -0
- pylzt-0.1.0/pyproject.toml +100 -0
- pylzt-0.1.0/src/pylzt/__init__.py +139 -0
- pylzt-0.1.0/src/pylzt/__main__.py +50 -0
- pylzt-0.1.0/src/pylzt/client.py +485 -0
- pylzt-0.1.0/src/pylzt/config.py +69 -0
- pylzt-0.1.0/src/pylzt/enums/__init__.py +0 -0
- pylzt-0.1.0/src/pylzt/enums/antipublic.py +41 -0
- pylzt-0.1.0/src/pylzt/enums/forum.py +136 -0
- pylzt-0.1.0/src/pylzt/enums/market.py +497 -0
- pylzt-0.1.0/src/pylzt/errors.py +342 -0
- pylzt-0.1.0/src/pylzt/export/__init__.py +0 -0
- pylzt-0.1.0/src/pylzt/export/resumable_exporter.py +51 -0
- pylzt-0.1.0/src/pylzt/facades/__init__.py +0 -0
- pylzt-0.1.0/src/pylzt/facades/_namespace.py +122 -0
- pylzt-0.1.0/src/pylzt/facades/_sync_namespace.py +77 -0
- pylzt-0.1.0/src/pylzt/facades/antipublic.py +145 -0
- pylzt-0.1.0/src/pylzt/facades/forum.py +2211 -0
- pylzt-0.1.0/src/pylzt/facades/market.py +5429 -0
- pylzt-0.1.0/src/pylzt/facades/sync_antipublic.py +140 -0
- pylzt-0.1.0/src/pylzt/facades/sync_forum.py +2148 -0
- pylzt-0.1.0/src/pylzt/facades/sync_market.py +5340 -0
- pylzt-0.1.0/src/pylzt/lib/__init__.py +1 -0
- pylzt-0.1.0/src/pylzt/lib/asyncio_utils.py +23 -0
- pylzt-0.1.0/src/pylzt/lib/batch.py +399 -0
- pylzt-0.1.0/src/pylzt/lib/cache.py +65 -0
- pylzt-0.1.0/src/pylzt/lib/clock.py +48 -0
- pylzt-0.1.0/src/pylzt/lib/concurrency.py +72 -0
- pylzt-0.1.0/src/pylzt/lib/media_storage.py +83 -0
- pylzt-0.1.0/src/pylzt/lib/metrics.py +36 -0
- pylzt-0.1.0/src/pylzt/lib/retry.py +60 -0
- pylzt-0.1.0/src/pylzt/media.py +31 -0
- pylzt-0.1.0/src/pylzt/methods/__init__.py +1 -0
- pylzt-0.1.0/src/pylzt/methods/antipublic_account.py +58 -0
- pylzt-0.1.0/src/pylzt/methods/antipublic_check.py +32 -0
- pylzt-0.1.0/src/pylzt/methods/antipublic_info.py +42 -0
- pylzt-0.1.0/src/pylzt/methods/antipublic_search.py +72 -0
- pylzt-0.1.0/src/pylzt/methods/balances.py +66 -0
- pylzt-0.1.0/src/pylzt/methods/base.py +177 -0
- pylzt-0.1.0/src/pylzt/methods/catalog.py +79 -0
- pylzt-0.1.0/src/pylzt/methods/categories.py +67 -0
- pylzt-0.1.0/src/pylzt/methods/conversations.py +47 -0
- pylzt-0.1.0/src/pylzt/methods/forum_assets.py +31 -0
- pylzt-0.1.0/src/pylzt/methods/forum_authentication.py +31 -0
- pylzt-0.1.0/src/pylzt/methods/forum_batch_requests.py +50 -0
- pylzt-0.1.0/src/pylzt/methods/forum_categories.py +61 -0
- pylzt-0.1.0/src/pylzt/methods/forum_chatbox.py +159 -0
- pylzt-0.1.0/src/pylzt/methods/forum_content_tagging.py +102 -0
- pylzt-0.1.0/src/pylzt/methods/forum_conversations.py +426 -0
- pylzt-0.1.0/src/pylzt/methods/forum_forms.py +47 -0
- pylzt-0.1.0/src/pylzt/methods/forum_forums.py +148 -0
- pylzt-0.1.0/src/pylzt/methods/forum_link_forums.py +52 -0
- pylzt-0.1.0/src/pylzt/methods/forum_notifications.py +56 -0
- pylzt-0.1.0/src/pylzt/methods/forum_pages.py +59 -0
- pylzt-0.1.0/src/pylzt/methods/forum_post_comments.py +38 -0
- pylzt-0.1.0/src/pylzt/methods/forum_posts.py +137 -0
- pylzt-0.1.0/src/pylzt/methods/forum_profile_post_comments.py +89 -0
- pylzt-0.1.0/src/pylzt/methods/forum_profile_posts.py +159 -0
- pylzt-0.1.0/src/pylzt/methods/forum_searching.py +227 -0
- pylzt-0.1.0/src/pylzt/methods/forum_threads.py +549 -0
- pylzt-0.1.0/src/pylzt/methods/forum_users.py +493 -0
- pylzt-0.1.0/src/pylzt/methods/market_account_managing.py +24 -0
- pylzt-0.1.0/src/pylzt/methods/market_account_publishing.py +194 -0
- pylzt-0.1.0/src/pylzt/methods/market_account_purchasing.py +112 -0
- pylzt-0.1.0/src/pylzt/methods/market_accounts_list.py +305 -0
- pylzt-0.1.0/src/pylzt/methods/market_accounts_managing.py +760 -0
- pylzt-0.1.0/src/pylzt/methods/market_batch_requests.py +50 -0
- pylzt-0.1.0/src/pylzt/methods/market_cart.py +72 -0
- pylzt-0.1.0/src/pylzt/methods/market_category_search.py +2638 -0
- pylzt-0.1.0/src/pylzt/methods/market_custom_discounts.py +24 -0
- pylzt-0.1.0/src/pylzt/methods/market_imap.py +29 -0
- pylzt-0.1.0/src/pylzt/methods/market_invoices.py +64 -0
- pylzt-0.1.0/src/pylzt/methods/market_payments.py +188 -0
- pylzt-0.1.0/src/pylzt/methods/market_profile.py +31 -0
- pylzt-0.1.0/src/pylzt/methods/market_proxy.py +25 -0
- pylzt-0.1.0/src/pylzt/methods/market_tags.py +45 -0
- pylzt-0.1.0/src/pylzt/methods/notifications.py +50 -0
- pylzt-0.1.0/src/pylzt/methods/payments.py +29 -0
- pylzt-0.1.0/src/pylzt/methods/users.py +28 -0
- pylzt-0.1.0/src/pylzt/models/__init__.py +1 -0
- pylzt-0.1.0/src/pylzt/models/antipublic/__init__.py +14 -0
- pylzt-0.1.0/src/pylzt/models/antipublic/extended_stats.py +19 -0
- pylzt-0.1.0/src/pylzt/models/antipublic/public_count_lines_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/antipublic/threads.py +19 -0
- pylzt-0.1.0/src/pylzt/models/balance.py +27 -0
- pylzt-0.1.0/src/pylzt/models/base.py +74 -0
- pylzt-0.1.0/src/pylzt/models/category.py +19 -0
- pylzt-0.1.0/src/pylzt/models/conversation.py +85 -0
- pylzt-0.1.0/src/pylzt/models/forum/__init__.py +212 -0
- pylzt-0.1.0/src/pylzt/models/forum/categories_list_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/category.py +25 -0
- pylzt-0.1.0/src/pylzt/models/forum/category_links.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/category_permissions.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/chatbox_index_response.py +24 -0
- pylzt-0.1.0/src/pylzt/models/forum/claim.py +26 -0
- pylzt-0.1.0/src/pylzt/models/forum/content.py +55 -0
- pylzt-0.1.0/src/pylzt/models/forum/content_contest.py +37 -0
- pylzt-0.1.0/src/pylzt/models/forum/content_first_post.py +49 -0
- pylzt-0.1.0/src/pylzt/models/forum/content_links.py +26 -0
- pylzt-0.1.0/src/pylzt/models/forum/content_permissions.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/content_thread_prefixe.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/contest_permissions.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_edit_message.py +41 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message.py +38 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message_links.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_message_permissions.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_messages_list_response.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/conversations_search_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/data_data_total_links_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/field_choice.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/field_field_choices.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/first_post_delete_info.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/first_post_links.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/first_post_permissions.py +25 -0
- pylzt-0.1.0/src/pylzt/models/forum/form.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/form_field.py +26 -0
- pylzt-0.1.0/src/pylzt/models/forum/forms_create_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/forms_list_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum.py +39 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_feed_option.py +37 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_forum_prefixe.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_links.py +24 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_permissions.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_prefixe_group_prefixe.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/forum_status_message_response.py +17 -0
- pylzt-0.1.0/src/pylzt/models/forum/forums_get_feed_options_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/forums_grouped_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/forums_list_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/forums_list_tab.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/ignore.py +56 -0
- pylzt-0.1.0/src/pylzt/models/forum/ignore_custom_fields.py +34 -0
- pylzt-0.1.0/src/pylzt/models/forum/ignore_rendered.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/leaderboard.py +39 -0
- pylzt-0.1.0/src/pylzt/models/forum/leaderboard_rendered.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/leaderboard_uniq_banner.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/link_forum.py +26 -0
- pylzt-0.1.0/src/pylzt/models/forum/link_forum_links.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/links.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/links_list_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/message.py +27 -0
- pylzt-0.1.0/src/pylzt/models/forum/message_links.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/message_permissions.py +24 -0
- pylzt-0.1.0/src/pylzt/models/forum/message_recipient.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/message_room.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/o_auth_token_response.py +28 -0
- pylzt-0.1.0/src/pylzt/models/forum/page.py +25 -0
- pylzt-0.1.0/src/pylzt/models/forum/page_links.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/pages_list_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/permissions.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/permissions_bump.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/post.py +48 -0
- pylzt-0.1.0/src/pylzt/models/forum/post_thread.py +54 -0
- pylzt-0.1.0/src/pylzt/models/forum/profile_thread_links.py +25 -0
- pylzt-0.1.0/src/pylzt/models/forum/profile_thread_permissions.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/rendered_avatars.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/room.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/rooms_online.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/search_all_permissions_bump.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/search_all_response.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/search_all_user.py +78 -0
- pylzt-0.1.0/src/pylzt/models/forum/stats.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/stats_market.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/tab.py +31 -0
- pylzt-0.1.0/src/pylzt/models/forum/trophy.py +30 -0
- pylzt-0.1.0/src/pylzt/models/forum/trophy_progresse.py +27 -0
- pylzt-0.1.0/src/pylzt/models/forum/trophy_progresse_progress.py +22 -0
- pylzt-0.1.0/src/pylzt/models/forum/user.py +41 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_custom_fields.py +31 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_edit_permissions.py +28 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_field.py +28 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_following_user.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_ignored_info.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_links.py +27 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_permissions.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_profile_thread.py +46 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_rendered.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_uniq_banner.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_user_external_authentication.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_user_following.py +19 -0
- pylzt-0.1.0/src/pylzt/models/forum/user_user_group.py +27 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_claims_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_ignored_user.py +53 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_likes_response.py +23 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_list_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_sa_reset_response.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_secret_answer_types_data.py +18 -0
- pylzt-0.1.0/src/pylzt/models/forum/users_trophies_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/lot.py +152 -0
- pylzt-0.1.0/src/pylzt/models/market/__init__.py +262 -0
- pylzt-0.1.0/src/pylzt/models/market/author_field.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/author_links.py +25 -0
- pylzt-0.1.0/src/pylzt/models/market/author_permissions.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/base_item.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/battle_net_item.py +105 -0
- pylzt-0.1.0/src/pylzt/models/market/calculator.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/cart_get_response.py +44 -0
- pylzt-0.1.0/src/pylzt/models/market/category_discord_item_seller.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/category_response.py +28 -0
- pylzt-0.1.0/src/pylzt/models/market/category_steam_list.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/claim.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/claim_author.py +42 -0
- pylzt-0.1.0/src/pylzt/models/market/code_data.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/codes.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/currency_list.py +78 -0
- pylzt-0.1.0/src/pylzt/models/market/currency_list_btc.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/currency_list_rub.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/custom_discounts_get_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/discord_item.py +98 -0
- pylzt-0.1.0/src/pylzt/models/market/discount.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/ea_item.py +114 -0
- pylzt-0.1.0/src/pylzt/models/market/email_letters_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/epic_games_item.py +112 -0
- pylzt-0.1.0/src/pylzt/models/market/escape_from_tarkov_item.py +113 -0
- pylzt-0.1.0/src/pylzt/models/market/fortnite_item.py +117 -0
- pylzt-0.1.0/src/pylzt/models/market/gifts_item.py +81 -0
- pylzt-0.1.0/src/pylzt/models/market/hytale_item.py +94 -0
- pylzt-0.1.0/src/pylzt/models/market/instagram_item.py +95 -0
- pylzt-0.1.0/src/pylzt/models/market/invoice.py +33 -0
- pylzt-0.1.0/src/pylzt/models/market/item_account_link.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_apex_legends.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/item_battlenet_game.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/item_battlenet_transaction.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_bump_settings.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_buyer.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_category.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_code_data_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_eg_game.py +27 -0
- pylzt-0.1.0/src/pylzt/models/market/item_eg_transaction.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_extra_price.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/item_fortnite_past_season.py +28 -0
- pylzt-0.1.0/src/pylzt/models/market/item_fortnite_skin.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/item_guarantee.py +25 -0
- pylzt-0.1.0/src/pylzt/models/market/item_id_tag_added_tag_id_delete_tags_response.py +22 -0
- pylzt-0.1.0/src/pylzt/models/market/item_login_data.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/item_lol_inventory.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/item_public_tag.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_r6_operator.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_roblox_game_donation.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_roblox_game_donations_detail.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_seller.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/item_shop_counts.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_socialclub_game.py +29 -0
- pylzt-0.1.0/src/pylzt/models/market/item_steam_full_games.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_steam_transaction.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/item_stickers.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_telegram_group_counters.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/item_uplay_game.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/item_valorant_inventory.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/item_wf_server.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/letter.py +22 -0
- pylzt-0.1.0/src/pylzt/models/market/list_user_item.py +100 -0
- pylzt-0.1.0/src/pylzt/models/market/list_user_response.py +49 -0
- pylzt-0.1.0/src/pylzt/models/market/list_viewed_response.py +28 -0
- pylzt-0.1.0/src/pylzt/models/market/llm_item.py +101 -0
- pylzt-0.1.0/src/pylzt/models/market/login_data.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/ma_file.py +28 -0
- pylzt-0.1.0/src/pylzt/models/market/ma_file_session.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_bulk_action_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_bulk_get_item.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_bulk_get_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_change_password_response.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_steam_inventory_value_data.py +30 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_steam_inventory_value_item.py +28 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_telegram_code_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/managing_temp_email_password_item.py +17 -0
- pylzt-0.1.0/src/pylzt/models/market/market_status_message_response.py +17 -0
- pylzt-0.1.0/src/pylzt/models/market/minecraft_item.py +112 -0
- pylzt-0.1.0/src/pylzt/models/market/payments_currency_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/payments_fee_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/payments_invoice_list_response.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/profile_claims_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/profile_get_user.py +93 -0
- pylzt-0.1.0/src/pylzt/models/market/providers_bep20.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/proxy.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/proxy_proxy.py +23 -0
- pylzt-0.1.0/src/pylzt/models/market/publishing_check_item.py +101 -0
- pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_buyer.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_guarantee.py +26 -0
- pylzt-0.1.0/src/pylzt/models/market/publishing_check_item_seller.py +27 -0
- pylzt-0.1.0/src/pylzt/models/market/publishing_fast_sell_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/purchasing_check_item.py +107 -0
- pylzt-0.1.0/src/pylzt/models/market/purchasing_check_item_seller.py +27 -0
- pylzt-0.1.0/src/pylzt/models/market/purchasing_check_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/purchasing_confirm_response.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/query_data_app_id_response.py +22 -0
- pylzt-0.1.0/src/pylzt/models/market/rendered_avatars.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/rendered_backgrounds.py +18 -0
- pylzt-0.1.0/src/pylzt/models/market/riot_item.py +146 -0
- pylzt-0.1.0/src/pylzt/models/market/roblox_item.py +113 -0
- pylzt-0.1.0/src/pylzt/models/market/social_club_item.py +118 -0
- pylzt-0.1.0/src/pylzt/models/market/stats.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/stats_market.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/status_item_response.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/steam_item.py +204 -0
- pylzt-0.1.0/src/pylzt/models/market/supercell_item.py +123 -0
- pylzt-0.1.0/src/pylzt/models/market/system.py +33 -0
- pylzt-0.1.0/src/pylzt/models/market/system_providers.py +31 -0
- pylzt-0.1.0/src/pylzt/models/market/tag.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/telegram_item.py +98 -0
- pylzt-0.1.0/src/pylzt/models/market/tik_tok_item.py +106 -0
- pylzt-0.1.0/src/pylzt/models/market/uplay_item.py +127 -0
- pylzt-0.1.0/src/pylzt/models/market/user.py +22 -0
- pylzt-0.1.0/src/pylzt/models/market/user_balance.py +25 -0
- pylzt-0.1.0/src/pylzt/models/market/user_custom_fields.py +38 -0
- pylzt-0.1.0/src/pylzt/models/market/user_dob.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/user_domain_zone.py +20 -0
- pylzt-0.1.0/src/pylzt/models/market/user_item_states.py +31 -0
- pylzt-0.1.0/src/pylzt/models/market/user_item_states_discount_request.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/user_item_states_stickied.py +19 -0
- pylzt-0.1.0/src/pylzt/models/market/user_rendered.py +21 -0
- pylzt-0.1.0/src/pylzt/models/market/user_telegram_client.py +24 -0
- pylzt-0.1.0/src/pylzt/models/market/vpn_item.py +85 -0
- pylzt-0.1.0/src/pylzt/models/market/warface_item.py +97 -0
- pylzt-0.1.0/src/pylzt/models/notification.py +42 -0
- pylzt-0.1.0/src/pylzt/models/payment.py +100 -0
- pylzt-0.1.0/src/pylzt/models/profile.py +27 -0
- pylzt-0.1.0/src/pylzt/pagination.py +64 -0
- pylzt-0.1.0/src/pylzt/plugins.py +46 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/__init__.py +0 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/base.py +75 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/health.py +78 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/round_robin.py +77 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/source.py +93 -0
- pylzt-0.1.0/src/pylzt/proxy_pool/sticky.py +109 -0
- pylzt-0.1.0/src/pylzt/py.typed +0 -0
- pylzt-0.1.0/src/pylzt/storage/__init__.py +17 -0
- pylzt-0.1.0/src/pylzt/storage/batch.py +100 -0
- pylzt-0.1.0/src/pylzt/storage/cursor.py +54 -0
- pylzt-0.1.0/src/pylzt/sync/__init__.py +5 -0
- pylzt-0.1.0/src/pylzt/sync/client.py +46 -0
- pylzt-0.1.0/src/pylzt/sync/runner.py +73 -0
- pylzt-0.1.0/src/pylzt/token_pool/__init__.py +1 -0
- pylzt-0.1.0/src/pylzt/token_pool/_static.py +68 -0
- pylzt-0.1.0/src/pylzt/token_pool/base.py +54 -0
- pylzt-0.1.0/src/pylzt/token_pool/bucket.py +113 -0
- pylzt-0.1.0/src/pylzt/token_pool/governor.py +101 -0
- pylzt-0.1.0/src/pylzt/token_pool/rate_limit.py +46 -0
- pylzt-0.1.0/src/pylzt/token_pool/round_robin.py +115 -0
- pylzt-0.1.0/src/pylzt/token_pool/selector.py +42 -0
- pylzt-0.1.0/src/pylzt/transport/__init__.py +1 -0
- pylzt-0.1.0/src/pylzt/transport/base.py +163 -0
- pylzt-0.1.0/src/pylzt/transport/middleware.py +127 -0
- pylzt-0.1.0/src/pylzt/transport/session.py +162 -0
- pylzt-0.1.0/src/pylzt/types.py +179 -0
- pylzt-0.1.0/tests/dev_codegen/test_diff.py +95 -0
- pylzt-0.1.0/tests/dev_codegen/test_pipeline.py +59 -0
- pylzt-0.1.0/tests/pylzt/contracts/test_cache_contract.py +34 -0
- pylzt-0.1.0/tests/pylzt/contracts/test_transport_contract.py +111 -0
- pylzt-0.1.0/tests/pylzt/e2e/test_live_read.py +293 -0
- pylzt-0.1.0/tests/pylzt/test_batch.py +290 -0
- pylzt-0.1.0/tests/pylzt/test_bound_model.py +117 -0
- pylzt-0.1.0/tests/pylzt/test_cache.py +86 -0
- pylzt-0.1.0/tests/pylzt/test_client_batching.py +154 -0
- pylzt-0.1.0/tests/pylzt/test_client_loop.py +129 -0
- pylzt-0.1.0/tests/pylzt/test_client_plugin_discovery.py +113 -0
- pylzt-0.1.0/tests/pylzt/test_client_reconfigure.py +67 -0
- pylzt-0.1.0/tests/pylzt/test_client_request.py +41 -0
- pylzt-0.1.0/tests/pylzt/test_concurrency.py +118 -0
- pylzt-0.1.0/tests/pylzt/test_cursor_storage.py +44 -0
- pylzt-0.1.0/tests/pylzt/test_error_registry.py +96 -0
- pylzt-0.1.0/tests/pylzt/test_governor.py +68 -0
- pylzt-0.1.0/tests/pylzt/test_media.py +253 -0
- pylzt-0.1.0/tests/pylzt/test_method_as_class.py +66 -0
- pylzt-0.1.0/tests/pylzt/test_methods_declarative.py +145 -0
- pylzt-0.1.0/tests/pylzt/test_namespaces.py +115 -0
- pylzt-0.1.0/tests/pylzt/test_pagination.py +60 -0
- pylzt-0.1.0/tests/pylzt/test_parse.py +92 -0
- pylzt-0.1.0/tests/pylzt/test_plugins.py +112 -0
- pylzt-0.1.0/tests/pylzt/test_proxy_pool.py +253 -0
- pylzt-0.1.0/tests/pylzt/test_rate_limited_governor.py +123 -0
- pylzt-0.1.0/tests/pylzt/test_resumable_exporter.py +68 -0
- pylzt-0.1.0/tests/pylzt/test_session_middleware.py +101 -0
- pylzt-0.1.0/tests/pylzt/test_sync.py +105 -0
- pylzt-0.1.0/tests/pylzt/test_token_pool.py +222 -0
- pylzt-0.1.0/tests/test_entry_helpers.py +72 -0
- 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
|
+
[](https://github.com/open-lzt/pylzt/actions/workflows/ci.yml)
|
|
32
|
+
[](https://www.python.org/)
|
|
33
|
+
[](https://docs.pydantic.dev/)
|
|
34
|
+
[](https://mypy-lang.org/)
|
|
35
|
+
[](https://docs.astral.sh/ruff/)
|
|
36
|
+
[](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).
|