From 66bcd22198a9742c651a782d39252118dacbf1e9 Mon Sep 17 00:00:00 2001 From: bohd4nx Date: Fri, 29 May 2026 22:11:03 +0300 Subject: [PATCH] feat: update constants and validation for stars and payment methods; refactor enums for clarity --- pyfragment/client.py | 9 ++++--- pyfragment/core/constants.py | 25 ++++++------------ pyfragment/core/cookies.py | 7 +++--- pyfragment/domains/giveaways/giveaway.py | 16 ++++++------ pyfragment/domains/purchases/purchase.py | 14 +++++------ pyfragment/exceptions.py | 4 +-- pyfragment/models/enums.py | 32 +++++++++++++++++++++--- 7 files changed, 62 insertions(+), 45 deletions(-) diff --git a/pyfragment/client.py b/pyfragment/client.py index aa2bd11..0597175 100644 --- a/pyfragment/client.py +++ b/pyfragment/client.py @@ -1,7 +1,7 @@ from __future__ import annotations import json -from typing import Any, cast, get_args +from typing import Any, cast from pyfragment.core.constants import DEFAULT_TIMEOUT, FRAGMENT_BASE_URL, REQUIRED_COOKIE_KEYS from pyfragment.domains.ads.service import AdsService @@ -82,13 +82,14 @@ class FragmentClient: @staticmethod def _normalize_wallet_version(wallet_version: str) -> WalletVersion: version = wallet_version.strip().upper() - if version not in get_args(WalletVersion): + try: + return WalletVersion(version) + except ValueError: raise ConfigurationError( ConfigurationError.UNSUPPORTED_VERSION.format( - version=version, supported=", ".join(sorted(get_args(WalletVersion))) + version=version, supported=", ".join(sorted(m.value for m in WalletVersion)) ) ) - return cast(WalletVersion, version) def __init__( self, diff --git a/pyfragment/core/constants.py b/pyfragment/core/constants.py index 23a3ef0..4fc2ba7 100644 --- a/pyfragment/core/constants.py +++ b/pyfragment/core/constants.py @@ -7,6 +7,14 @@ from tonutils.contracts.wallet import WalletV4R2, WalletV5R1 WALLET_CLASSES: dict[str, Any] = {"V4R2": WalletV4R2, "V5R1": WalletV5R1} +# Stars limits +STARS_PURCHASE_MIN: int = 50 +STARS_PURCHASE_MAX: int = 10_000 +STARS_GIVEAWAY_MIN: int = 500 +STARS_GIVEAWAY_MAX: int = 1_000_000 +STARS_WINNERS_MIN: int = 1 +STARS_WINNERS_MAX: int = 5 + MIN_TON_BALANCE: float = 0.33 USDT_TON_MASTER_ADDRESS: str = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs" MIN_USDT_BALANCE: float = 0.75 @@ -25,23 +33,6 @@ ADS_TOPUP_PAGE: str = f"{FRAGMENT_BASE_URL}/ads/topup" NUMBERS_PAGE: str = f"{FRAGMENT_BASE_URL}/numbers" GIFTS_PAGE: str = f"{FRAGMENT_BASE_URL}/gifts" -SUPPORTED_BROWSERS: frozenset[str] = frozenset( - { - "arc", - "brave", - "chrome", - "chromium", - "chromium_based", - "edge", - "firefox", - "firefox_based", - "librewolf", - "opera", - "opera_gx", - "safari", - "vivaldi", - } -) DEVICE: str = json.dumps( { diff --git a/pyfragment/core/cookies.py b/pyfragment/core/cookies.py index 12cb6f1..c800673 100644 --- a/pyfragment/core/cookies.py +++ b/pyfragment/core/cookies.py @@ -4,9 +4,10 @@ import importlib from datetime import datetime, timezone from typing import Any -from pyfragment.core.constants import FRAGMENT_BASE_URL, FRAGMENT_DOMAIN, REQUIRED_COOKIE_KEYS, SUPPORTED_BROWSERS +from pyfragment.core.constants import FRAGMENT_BASE_URL, FRAGMENT_DOMAIN, REQUIRED_COOKIE_KEYS from pyfragment.exceptions import CookieError from pyfragment.models.cookies import CookieResult +from pyfragment.models.enums import SupportedBrowser try: import rookiepy @@ -18,8 +19,8 @@ def get_cookies_from_browser(browser: str = "chrome") -> CookieResult: global rookiepy key = browser.lower() - if key not in SUPPORTED_BROWSERS: - supported = ", ".join(sorted(SUPPORTED_BROWSERS)) + if key not in SupportedBrowser._value2member_map_: + supported = ", ".join(sorted(b.value for b in SupportedBrowser)) raise CookieError(CookieError.UNSUPPORTED_BROWSER.format(browser=browser, supported=supported)) try: diff --git a/pyfragment/domains/giveaways/giveaway.py b/pyfragment/domains/giveaways/giveaway.py index e8ab668..ffe8091 100644 --- a/pyfragment/domains/giveaways/giveaway.py +++ b/pyfragment/domains/giveaways/giveaway.py @@ -3,9 +3,9 @@ from __future__ import annotations import json import logging import random -from typing import TYPE_CHECKING, get_args +from typing import TYPE_CHECKING -from pyfragment.core.constants import DEVICE, PREMIUM_GIVEAWAY_PAGE, STARS_GIVEAWAY_PAGE +from pyfragment.core.constants import DEVICE, PREMIUM_GIVEAWAY_PAGE, STARS_GIVEAWAY_PAGE, STARS_GIVEAWAY_MIN, STARS_GIVEAWAY_MAX, STARS_WINNERS_MIN, STARS_WINNERS_MAX from pyfragment.domains.payments import parse_required_payment_amount from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.transaction import process_transaction @@ -34,15 +34,15 @@ async def giveaway_stars( amount: int, payment_method: PaymentMethod = "ton", ) -> StarsGiveawayResult: - if not isinstance(winners, int) or not (1 <= winners <= 5): + if not isinstance(winners, int) or not (STARS_WINNERS_MIN <= winners <= STARS_WINNERS_MAX): raise ConfigurationError(ConfigurationError.INVALID_WINNERS_STARS) - if not isinstance(amount, int) or not (500 <= amount <= 1_000_000): + if not isinstance(amount, int) or not (STARS_GIVEAWAY_MIN <= amount <= STARS_GIVEAWAY_MAX): raise ConfigurationError(ConfigurationError.INVALID_STARS_PER_WINNER) - if payment_method not in get_args(PaymentMethod): + if payment_method not in PaymentMethod._value2member_map_: raise ConfigurationError( ConfigurationError.INVALID_PAYMENT_METHOD.format( method=payment_method, - supported=", ".join(sorted(get_args(PaymentMethod))), + supported=", ".join(sorted(m.value for m in PaymentMethod)), ) ) @@ -128,11 +128,11 @@ async def giveaway_premium( raise ConfigurationError(ConfigurationError.INVALID_WINNERS_PREMIUM) if months not in (3, 6, 12): raise ConfigurationError(ConfigurationError.INVALID_MONTHS) - if payment_method not in get_args(PaymentMethod): + if payment_method not in PaymentMethod._value2member_map_: raise ConfigurationError( ConfigurationError.INVALID_PAYMENT_METHOD.format( method=payment_method, - supported=", ".join(sorted(get_args(PaymentMethod))), + supported=", ".join(sorted(PaymentMethod._value2member_map_)), ) ) diff --git a/pyfragment/domains/purchases/purchase.py b/pyfragment/domains/purchases/purchase.py index 5d60c5d..b8aaf63 100644 --- a/pyfragment/domains/purchases/purchase.py +++ b/pyfragment/domains/purchases/purchase.py @@ -3,9 +3,9 @@ from __future__ import annotations import json import logging import time -from typing import TYPE_CHECKING, get_args +from typing import TYPE_CHECKING -from pyfragment.core.constants import DEVICE, PREMIUM_PAGE, STARS_PAGE +from pyfragment.core.constants import DEVICE, PREMIUM_PAGE, STARS_PAGE, STARS_PURCHASE_MIN, STARS_PURCHASE_MAX from pyfragment.domains.payments import parse_required_payment_amount from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.transaction import process_transaction @@ -34,13 +34,13 @@ async def purchase_stars( show_sender: bool = True, payment_method: PaymentMethod = "ton", ) -> StarsResult: - if not isinstance(amount, int) or not (50 <= amount <= 1_000_000): + if not isinstance(amount, int) or not (STARS_PURCHASE_MIN <= amount <= STARS_PURCHASE_MAX): raise ConfigurationError(ConfigurationError.INVALID_STARS_AMOUNT) - if payment_method not in get_args(PaymentMethod): + if payment_method not in PaymentMethod._value2member_map_: raise ConfigurationError( ConfigurationError.INVALID_PAYMENT_METHOD.format( method=payment_method, - supported=", ".join(sorted(get_args(PaymentMethod))), + supported=", ".join(sorted(PaymentMethod._value2member_map_)), ) ) @@ -117,11 +117,11 @@ async def purchase_premium( ) -> PremiumResult: if months not in (3, 6, 12): raise ConfigurationError(ConfigurationError.INVALID_MONTHS) - if payment_method not in get_args(PaymentMethod): + if payment_method not in PaymentMethod._value2member_map_: raise ConfigurationError( ConfigurationError.INVALID_PAYMENT_METHOD.format( method=payment_method, - supported=", ".join(sorted(get_args(PaymentMethod))), + supported=", ".join(sorted(PaymentMethod._value2member_map_)), ) ) diff --git a/pyfragment/exceptions.py b/pyfragment/exceptions.py index d1337f6..21c7ca3 100644 --- a/pyfragment/exceptions.py +++ b/pyfragment/exceptions.py @@ -19,7 +19,7 @@ class ConfigurationError(ClientError): "Invalid Tonapi API key: expected at least 68 characters, got {length}. Get a key at https://tonconsole.com." ) INVALID_MONTHS = "Invalid Premium duration: choose 3, 6, or 12 months." - INVALID_STARS_AMOUNT = "Invalid Stars amount: must be an integer between 50 and 1,000,000." + INVALID_STARS_AMOUNT = "Invalid Stars amount: must be an integer between 50 and 10,000." INVALID_TON_AMOUNT = "Invalid TON amount: must be an integer between 1 and 1,000,000,000." INVALID_USERNAME = ( "Invalid username '{username}'. " @@ -27,7 +27,7 @@ class ConfigurationError(ClientError): ) INVALID_WINNERS_STARS = "Invalid winners count: must be an integer between 1 and 5." INVALID_WINNERS_PREMIUM = "Invalid winners count: must be an integer between 1 and 24,000." - INVALID_STARS_PER_WINNER = "Invalid Stars per winner: must be an integer between 500 and 1,000,000." + INVALID_STARS_PER_WINNER = "Invalid Stars per winner: must be an integer between 500 and 1,000,000 (max total: 1,000,000)." INVALID_PAYMENT_METHOD = "Invalid payment method '{method}'. Supported values: {supported}." diff --git a/pyfragment/models/enums.py b/pyfragment/models/enums.py index 0c29bcf..a7f1c52 100644 --- a/pyfragment/models/enums.py +++ b/pyfragment/models/enums.py @@ -1,8 +1,32 @@ from __future__ import annotations -from typing import Literal +from enum import StrEnum -PaymentMethod = Literal["ton", "usdt_ton"] -WalletVersion = Literal["V4R2", "V5R1"] -__all__ = ["PaymentMethod", "WalletVersion"] +class PaymentMethod(StrEnum): + TON = "ton" + USDT_TON = "usdt_ton" + + +class WalletVersion(StrEnum): + V4R2 = "V4R2" + V5R1 = "V5R1" + + +class SupportedBrowser(StrEnum): + ARC = "arc" + BRAVE = "brave" + CHROME = "chrome" + CHROMIUM = "chromium" + CHROMIUM_BASED = "chromium_based" + EDGE = "edge" + FIREFOX = "firefox" + FIREFOX_BASED = "firefox_based" + LIBREWOLF = "librewolf" + OPERA = "opera" + OPERA_GX = "opera_gx" + SAFARI = "safari" + VIVALDI = "vivaldi" + + +__all__ = ["PaymentMethod", "SupportedBrowser", "WalletVersion"]