Refactor FragmentAPI to pyfragment

- Renamed the package from `fragmentapi` to `pyfragment` across all modules and tests.
- Removed the old wallet utility functions and replaced them with new implementations.
- Updated the `pyproject.toml` to reflect the new package name and repository links.
- Adjusted all import statements in tests to use the new package name.
- Implemented new methods for gifting Telegram Premium, Stars, and topping up TON balance.
- Added exception handling for various error scenarios in the API interactions.
- Created new utility functions for handling HTTP requests and decoding payloads.
- Established a clear structure for types and constants used throughout the library.
This commit is contained in:
bohd4nx
2026-03-15 22:07:01 +02:00
parent 7f269d9a87
commit 8135a9da7e
29 changed files with 68 additions and 68 deletions
+6 -6
View File
@@ -1,5 +1,5 @@
name: Bug report name: Bug report
description: Report an issue or unexpected behavior in FragmentAPI. description: Report an issue or unexpected behavior in pyfragment.
labels: labels:
- bug - bug
body: body:
@@ -7,7 +7,7 @@ body:
attributes: attributes:
label: Checklist label: Checklist
options: options:
- label: I am sure the error is coming from FragmentAPI code - label: I am sure the error is coming from pyfragment code
required: true required: true
- label: I have searched the issue tracker for similar bug reports, including closed ones - label: I have searched the issue tracker for similar bug reports, including closed ones
required: true required: true
@@ -35,8 +35,8 @@ body:
- type: input - type: input
attributes: attributes:
label: FragmentAPI version label: pyfragment version
description: Run `pip show fragmentapi` inside your virtualenv description: Run `pip show pyfragment` inside your virtualenv
placeholder: e.g. 2026.1.0 placeholder: e.g. 2026.1.0
validations: validations:
required: true required: true
@@ -74,7 +74,7 @@ body:
description: Provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if applicable. description: Provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if applicable.
placeholder: | placeholder: |
import asyncio import asyncio
from fragmentapi import FragmentClient from pyfragment import FragmentClient
async def main(): async def main():
client = FragmentClient(...) client = FragmentClient(...)
@@ -91,7 +91,7 @@ body:
Traceback (most recent call last): Traceback (most recent call last):
File "main.py", line 7, in main File "main.py", line 7, in main
... ...
fragmentapi.types.ParseError: ... pyfragment.types.ParseError: ...
render: sh render: sh
- type: textarea - type: textarea
+1 -1
View File
@@ -1,5 +1,5 @@
blank_issues_enabled: true blank_issues_enabled: true
contact_links: contact_links:
- name: Ask a question or start a discussion - name: Ask a question or start a discussion
url: https://github.com/bohd4nx/FragmentAPI/discussions url: https://github.com/bohd4nx/pyfragment/discussions
about: General questions, ideas, and community help go here — not in the issue tracker. about: General questions, ideas, and community help go here — not in the issue tracker.
+2 -2
View File
@@ -1,11 +1,11 @@
name: Feature request name: Feature request
description: Suggest an improvement or new feature for FragmentAPI. description: Suggest an improvement or new feature for pyfragment.
labels: labels:
- enhancement - enhancement
body: body:
- type: dropdown - type: dropdown
attributes: attributes:
label: FragmentAPI version label: pyfragment version
description: Which version are you running? description: Which version are you running?
options: options:
- latest - latest
+1 -1
View File
@@ -23,7 +23,7 @@ Describe the tests you ran to verify the change and list any relevant details.
**Test configuration:** **Test configuration:**
* OS: * OS:
* Python version: * Python version:
* FragmentAPI version: * pyfragment version:
## Checklist ## Checklist
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: environment:
name: pypi name: pypi
url: https://pypi.org/project/fragmentapi/ url: https://pypi.org/project/pyfragment/
permissions: permissions:
id-token: write id-token: write
+10 -10
View File
@@ -7,14 +7,14 @@
<b>Python library for the Fragment.com API — gift Telegram Stars, Premium, and top up TON Ads balance.</b> <b>Python library for the Fragment.com API — gift Telegram Stars, Premium, and top up TON Ads balance.</b>
</p> </p>
[![PyPI version](https://img.shields.io/pypi/v/fragmentapi?style=flat&color=blue)](https://pypi.org/project/fragmentapi/) [![PyPI version](https://img.shields.io/pypi/v/pyfragment?style=flat&color=blue)](https://pypi.org/project/pyfragment/)
[![PyPI downloads](https://img.shields.io/pypi/dm/fragmentapi?style=flat&color=brightgreen)](https://pypi.org/project/fragmentapi/) [![PyPI downloads](https://img.shields.io/pypi/dm/pyfragment?style=flat&color=brightgreen)](https://pypi.org/project/pyfragment/)
[![Python](https://img.shields.io/badge/Python-3.12+-3776AB?style=flat&logo=python&logoColor=white)](https://python.org) [![Python](https://img.shields.io/badge/Python-3.12+-3776AB?style=flat&logo=python&logoColor=white)](https://python.org)
[![License](https://img.shields.io/github/license/bohd4nx/FragmentAPI?style=flat&color=lightgrey)](LICENSE) [![License](https://img.shields.io/github/license/bohd4nx/pyfragment?style=flat&color=lightgrey)](LICENSE)
[![Stars](https://img.shields.io/github/stars/bohd4nx/FragmentAPI?style=flat&color=yellow)](https://github.com/bohd4nx/FragmentAPI/stargazers) [![Stars](https://img.shields.io/github/stars/bohd4nx/pyfragment?style=flat&color=yellow)](https://github.com/bohd4nx/pyfragment/stargazers)
[![CI](https://img.shields.io/github/actions/workflow/status/bohd4nx/FragmentAPI/tests.yml?style=flat&label=tests&logo=github)](https://github.com/bohd4nx/FragmentAPI/actions) [![CI](https://img.shields.io/github/actions/workflow/status/bohd4nx/pyfragment/tests.yml?style=flat&label=tests&logo=github)](https://github.com/bohd4nx/pyfragment/actions)
[Report Bug](https://github.com/bohd4nx/FragmentAPI/issues) · [Request Feature](https://github.com/bohd4nx/FragmentAPI/issues) · [**Donate TON**](https://app.tonkeeper.com/transfer/UQCppfw5DxWgdVHf3zkmZS8k1mt9oAUYxQLwq2fz3nhO8No5) [Report Bug](https://github.com/bohd4nx/pyfragment/issues) · [Request Feature](https://github.com/bohd4nx/pyfragment/issues) · [**Donate TON**](https://app.tonkeeper.com/transfer/UQCppfw5DxWgdVHf3zkmZS8k1mt9oAUYxQLwq2fz3nhO8No5)
</div> </div>
@@ -33,7 +33,7 @@
## 📦 Installation ## 📦 Installation
```bash ```bash
pip install fragmentapi pip install pyfragment
``` ```
Requires **Python 3.12+**. Requires **Python 3.12+**.
@@ -44,7 +44,7 @@ Requires **Python 3.12+**.
```python ```python
import asyncio import asyncio
from fragmentapi import FragmentClient from pyfragment import FragmentClient
client = FragmentClient( client = FragmentClient(
seed="word1 word2 ... word24", seed="word1 word2 ... word24",
@@ -146,10 +146,10 @@ Go to **Settings → Backup** → copy the 24 words.
## 🗂️ Error Handling ## 🗂️ Error Handling
All exceptions inherit from `FragmentError` — see [`fragmentapi/types/exceptions.py`](fragmentapi/types/exceptions.py) for the full list. All exceptions inherit from `FragmentError` — see [`pyfragment/types/exceptions.py`](pyfragment/types/exceptions.py) for the full list.
```python ```python
from fragmentapi import FragmentClient, UserNotFoundError, ConfigurationError, WalletError from pyfragment import FragmentClient, UserNotFoundError, ConfigurationError, WalletError
try: try:
result = await client.gift_stars("@unknown", amount=100) result = await client.gift_stars("@unknown", amount=100)
+1 -1
View File
@@ -7,7 +7,7 @@ wallet_version defaults to "V5R1" — change to "V4R2" for older wallets.
import asyncio import asyncio
from fragmentapi import FragmentClient from pyfragment import FragmentClient
SEED = "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13 word14 word15 word16 word17 word18 word19 word20 word21 word22 word23 word24" SEED = "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13 word14 word15 word16 word17 word18 word19 word20 word21 word22 word23 word24"
API_KEY = "YOUR_TONAPI_KEY" API_KEY = "YOUR_TONAPI_KEY"
+1 -1
View File
@@ -7,7 +7,7 @@ Set show_sender=False to send anonymously.
import asyncio import asyncio
from fragmentapi import ConfigurationError, FragmentClient, UserNotFoundError from pyfragment import ConfigurationError, FragmentClient, UserNotFoundError
SEED = "word1 word2 ... word24" SEED = "word1 word2 ... word24"
API_KEY = "YOUR_TONAPI_KEY" API_KEY = "YOUR_TONAPI_KEY"
+1 -1
View File
@@ -7,7 +7,7 @@ Set show_sender=False to send anonymously.
import asyncio import asyncio
from fragmentapi import ConfigurationError, FragmentClient, UserNotFoundError from pyfragment import ConfigurationError, FragmentClient, UserNotFoundError
SEED = "word1 word2 ... word24" SEED = "word1 word2 ... word24"
API_KEY = "YOUR_TONAPI_KEY" API_KEY = "YOUR_TONAPI_KEY"
+1 -1
View File
@@ -7,7 +7,7 @@ Your wallet must hold at least the topup amount + ~0.056 TON for gas.
import asyncio import asyncio
from fragmentapi import ConfigurationError, FragmentClient, UserNotFoundError, WalletError from pyfragment import ConfigurationError, FragmentClient, UserNotFoundError, WalletError
SEED = "word1 word2 ... word24" SEED = "word1 word2 ... word24"
API_KEY = "YOUR_TONAPI_KEY" API_KEY = "YOUR_TONAPI_KEY"
-5
View File
@@ -1,5 +0,0 @@
from fragmentapi.methods.premium import gift_premium
from fragmentapi.methods.stars import gift_stars
from fragmentapi.methods.ton import topup_ton
__all__ = ["gift_premium", "gift_stars", "topup_ton"]
@@ -3,8 +3,8 @@
# This source code is licensed under the MIT License found in the # This source code is licensed under the MIT License found in the
# LICENSE file in the root directory of this source tree. # LICENSE file in the root directory of this source tree.
from fragmentapi.client import FragmentClient from pyfragment.client import FragmentClient
from fragmentapi.types import ( from pyfragment.types import (
AdsTopupResult, AdsTopupResult,
ClientError, ClientError,
ConfigurationError, ConfigurationError,
@@ -1,9 +1,9 @@
import json import json
from fragmentapi.methods.premium import gift_premium from pyfragment.methods.premium import gift_premium
from fragmentapi.methods.stars import gift_stars from pyfragment.methods.stars import gift_stars
from fragmentapi.methods.ton import topup_ton from pyfragment.methods.ton import topup_ton
from fragmentapi.types import ( from pyfragment.types import (
REQUIRED_COOKIE_KEYS, REQUIRED_COOKIE_KEYS,
SUPPORTED_WALLET_VERSIONS, SUPPORTED_WALLET_VERSIONS,
AdsTopupResult, AdsTopupResult,
+5
View File
@@ -0,0 +1,5 @@
from pyfragment.methods.premium import gift_premium
from pyfragment.methods.stars import gift_stars
from pyfragment.methods.ton import topup_ton
__all__ = ["gift_premium", "gift_stars", "topup_ton"]
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
import httpx import httpx
from fragmentapi.types import ( from pyfragment.types import (
BASE_HEADERS, BASE_HEADERS,
DEVICE, DEVICE,
PREMIUM_PAGE, PREMIUM_PAGE,
@@ -15,7 +15,7 @@ from fragmentapi.types import (
UnexpectedError, UnexpectedError,
UserNotFoundError, UserNotFoundError,
) )
from fragmentapi.utils import ( from pyfragment.utils import (
execute_transaction_request, execute_transaction_request,
fragment_post, fragment_post,
get_account_info, get_account_info,
@@ -24,7 +24,7 @@ from fragmentapi.utils import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from fragmentapi.client import FragmentClient from pyfragment.client import FragmentClient
# Page-specific headers # Page-specific headers
HEADERS: dict[str, str] = { HEADERS: dict[str, str] = {
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
import httpx import httpx
from fragmentapi.types import ( from pyfragment.types import (
BASE_HEADERS, BASE_HEADERS,
DEVICE, DEVICE,
STARS_PAGE, STARS_PAGE,
@@ -14,7 +14,7 @@ from fragmentapi.types import (
UnexpectedError, UnexpectedError,
UserNotFoundError, UserNotFoundError,
) )
from fragmentapi.utils import ( from pyfragment.utils import (
execute_transaction_request, execute_transaction_request,
fragment_post, fragment_post,
get_account_info, get_account_info,
@@ -23,7 +23,7 @@ from fragmentapi.utils import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from fragmentapi.client import FragmentClient from pyfragment.client import FragmentClient
# Page-specific headers # Page-specific headers
HEADERS: dict[str, str] = { HEADERS: dict[str, str] = {
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
import httpx import httpx
from fragmentapi.types import ( from pyfragment.types import (
BASE_HEADERS, BASE_HEADERS,
DEVICE, DEVICE,
TON_PAGE, TON_PAGE,
@@ -14,7 +14,7 @@ from fragmentapi.types import (
UnexpectedError, UnexpectedError,
UserNotFoundError, UserNotFoundError,
) )
from fragmentapi.utils import ( from pyfragment.utils import (
execute_transaction_request, execute_transaction_request,
fragment_post, fragment_post,
get_account_info, get_account_info,
@@ -23,7 +23,7 @@ from fragmentapi.utils import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from fragmentapi.client import FragmentClient from pyfragment.client import FragmentClient
# Page-specific headers # Page-specific headers
HEADERS: dict[str, str] = { HEADERS: dict[str, str] = {
@@ -1,4 +1,4 @@
from fragmentapi.types.constants import ( from pyfragment.types.constants import (
BASE_HEADERS, BASE_HEADERS,
DEVICE, DEVICE,
MIN_TON_BALANCE, MIN_TON_BALANCE,
@@ -10,7 +10,7 @@ from fragmentapi.types.constants import (
WALLET_CLASSES, WALLET_CLASSES,
WalletVersion, WalletVersion,
) )
from fragmentapi.types.exceptions import ( from pyfragment.types.exceptions import (
ClientError, ClientError,
ConfigurationError, ConfigurationError,
CookieError, CookieError,
@@ -25,7 +25,7 @@ from fragmentapi.types.exceptions import (
VerificationError, VerificationError,
WalletError, WalletError,
) )
from fragmentapi.types.results import AdsTopupResult, PremiumResult, StarsResult from pyfragment.types.results import AdsTopupResult, PremiumResult, StarsResult
__all__ = [ __all__ = [
# constants # constants
@@ -1,5 +1,5 @@
class FragmentError(Exception): class FragmentError(Exception):
"""Base exception for all fragmentapi library errors.""" """Base exception for all pyfragment library errors."""
class ClientError(FragmentError): class ClientError(FragmentError):
@@ -1,11 +1,11 @@
from fragmentapi.utils.decoder import clean_decode from pyfragment.utils.decoder import clean_decode
from fragmentapi.utils.http import ( from pyfragment.utils.http import (
execute_transaction_request, execute_transaction_request,
fragment_post, fragment_post,
get_fragment_hash, get_fragment_hash,
parse_json_response, parse_json_response,
) )
from fragmentapi.utils.wallet import get_account_info, process_transaction from pyfragment.utils.wallet import get_account_info, process_transaction
__all__ = [ __all__ = [
"clean_decode", "clean_decode",
@@ -2,7 +2,7 @@ import base64
from pytoniq_core import Cell from pytoniq_core import Cell
from fragmentapi.types import ParseError from pyfragment.types import ParseError
def clean_decode(payload: str) -> str: def clean_decode(payload: str) -> str:
@@ -3,7 +3,7 @@ from typing import Any
import httpx import httpx
from fragmentapi.types import FragmentPageError, ParseError, VerificationError from pyfragment.types import FragmentPageError, ParseError, VerificationError
async def get_fragment_hash( async def get_fragment_hash(
@@ -4,11 +4,11 @@ from typing import TYPE_CHECKING, Any
from tonutils.clients import TonapiClient from tonutils.clients import TonapiClient
from tonutils.types import NetworkGlobalID from tonutils.types import NetworkGlobalID
from fragmentapi.types import MIN_TON_BALANCE, WALLET_CLASSES, TransactionError, WalletError from pyfragment.types import MIN_TON_BALANCE, WALLET_CLASSES, TransactionError, WalletError
from fragmentapi.utils.decoder import clean_decode from pyfragment.utils.decoder import clean_decode
if TYPE_CHECKING: if TYPE_CHECKING:
from fragmentapi.client import FragmentClient from pyfragment.client import FragmentClient
def _init_ton_client(client: "FragmentClient") -> TonapiClient: def _init_ton_client(client: "FragmentClient") -> TonapiClient:
+5 -5
View File
@@ -3,7 +3,7 @@ requires = ["hatchling"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[project] [project]
name = "fragmentapi" name = "pyfragment"
version = "2026.1.0" version = "2026.1.0"
description = "Python library for the Fragment.com API — gift Telegram Stars, Premium, and top up TON Ads balance." description = "Python library for the Fragment.com API — gift Telegram Stars, Premium, and top up TON Ads balance."
readme = "README.md" readme = "README.md"
@@ -39,12 +39,12 @@ dev = [
] ]
[project.urls] [project.urls]
Homepage = "https://github.com/bohd4nx/FragmentAPI" Homepage = "https://github.com/bohd4nx/pyfragment"
Repository = "https://github.com/bohd4nx/FragmentAPI" Repository = "https://github.com/bohd4nx/pyfragment"
Issues = "https://github.com/bohd4nx/FragmentAPI/issues" Issues = "https://github.com/bohd4nx/pyfragment/issues"
[tool.hatch.build.targets.wheel] [tool.hatch.build.targets.wheel]
packages = ["fragmentapi"] packages = ["pyfragment"]
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = ["tests"] testpaths = ["tests"]
+2 -2
View File
@@ -4,8 +4,8 @@ import re
import pytest import pytest
from fragmentapi.types import ParseError from pyfragment.types import ParseError
from fragmentapi.utils.decoder import clean_decode from pyfragment.utils.decoder import clean_decode
PAYLOADS = [ PAYLOADS = [
pytest.param( pytest.param(
+2 -2
View File
@@ -4,8 +4,8 @@ import json
import pytest import pytest
from fragmentapi import FragmentClient from pyfragment import FragmentClient
from fragmentapi.types import ConfigurationError, CookieError from pyfragment.types import ConfigurationError, CookieError
VALID_SEED = "abandon " * 23 + "about" VALID_SEED = "abandon " * 23 + "about"
VALID_API_KEY = "test_api_key" VALID_API_KEY = "test_api_key"
+2 -2
View File
@@ -5,8 +5,8 @@ import re
import pytest import pytest
from fragmentapi.types import BASE_HEADERS, STARS_PAGE from pyfragment.types import BASE_HEADERS, STARS_PAGE
from fragmentapi.utils import get_fragment_hash from pyfragment.utils import get_fragment_hash
@pytest.mark.asyncio @pytest.mark.asyncio