Python client library for TeleStore — Telegram-backed file storage
Project description
telestore
A lightweight Python client library for TeleStore — a free file-storage service that uses Telegram channels as its backend.
1. What is TeleStore?
TeleStore is a REST API service that lets you store files up to 2 GB inside Telegram channels — for free. It exposes a simple HTTP API that is authentication via an API key, making it easy to use as a drop-in file-storage backend for lightweight SaaS products or hobby projects. This library wraps that API into an ergonomic Python interface so you can go from zero to first upload in under 5 minutes.
→ Live instance: https://telestore.onrender.com
2. Installation
pip install telestore
For better MIME-type detection (strongly recommended), also install python-magic:
pip install telestore python-magic
# On Windows you may also need the libmagic binary:
pip install python-magic-bin
python-magic is entirely optional — the library falls back to filename-based detection via the standard library mimetypes module when it is not installed.
3. Getting Your API Key
- Sign up at https://telestore.onrender.com/auth/signup/
- Log in and navigate to https://telestore.onrender.com/api-keys/
- Click Generate Key, give it a name, and copy the key starting with
sk-
Keep your API key secret. Anyone who has it can upload files on your behalf.
4. Quickstart
From zero to first upload in under 10 lines:
from telestore import TeleStoreClient
client = TeleStoreClient(api_key="sk-your-api-key-here")
# Upload a file
result = client.upload("photo.jpg")
print(result.view_url) # share this link
# Upload JSON data directly
result = client.upload_json({"user": "alice", "score": 42})
data = client.download_json(result.file_id)
# Upload raw text
result = client.upload_text("Hello, TeleStore!")
text = client.download_text(result.file_id)
5. Usage Examples
Creating the client
from telestore import TeleStoreClient
client = TeleStoreClient(
api_key="sk-your-api-key-here",
base_url="https://telestore.onrender.com", # default — change for self-hosted
timeout=120, # seconds; default is 120
)
Uploading files
From a file path:
result = client.upload("path/to/document.pdf")
print(result.file_id) # opaque identifier — keep this private
print(result.view_url) # publicly accessible inline URL
print(result.download_url) # publicly accessible attachment URL
print(result.mime_type) # e.g. "application/pdf"
print(result.size_bytes) # size in bytes
From bytes:
data = b"raw binary content"
result = client.upload(data, filename="data.bin")
From a file-like object:
with open("archive.zip", "rb") as fh:
result = client.upload(fh)
From a remote URL:
result = client.url_upload("https://example.com/image.png")
Uploading typed content
Image (validates MIME type):
# Raises UploadError if the file is not actually an image.
result = client.upload_image("photo.jpg")
Plain text:
result = client.upload_text("Hello, world!", filename="greeting.txt")
# Custom encoding:
result = client.upload_text("こんにちは", filename="jp.txt", encoding="utf-8")
JSON dict:
result = client.upload_json({"key": "value", "items": [1, 2, 3]})
Downloading files
Into memory:
raw: bytes = client.download("abc123")
To disk:
from pathlib import Path
path = client.download("abc123", destination="downloads/file.bin")
# path is a pathlib.Path pointing to the saved file
As text:
text: str = client.download_text("abc123")
As JSON:
data: dict = client.download_json("abc123")
Getting URLs without a network call
view_url = client.get_url("abc123", mode="view") # inline
download_url = client.get_url("abc123", mode="download") # attachment
6. Configuration
| Parameter | Default | Description |
|---|---|---|
api_key |
(required) | Your TeleStore API key (sk-...). |
base_url |
https://telestore.onrender.com |
Change this only when using a self-hosted TeleStore instance. |
timeout |
120 |
Request timeout in seconds. Files larger than 50 MB use a slower Telethon-based upload path on the server, so the default is intentionally generous. |
Loading credentials from the environment:
import os
from dotenv import load_dotenv
from telestore import TeleStoreClient
load_dotenv() # reads .env file
client = TeleStoreClient(
api_key=os.environ["TELESTORE_API_KEY"],
base_url=os.getenv("TELESTORE_BASE_URL", "https://telestore.onrender.com"),
)
Copy .env.example to .env and fill it in:
TELESTORE_API_KEY=sk-your-api-key-here
TELESTORE_BASE_URL=https://telestore.onrender.com
7. Error Handling
All exceptions inherit from TeleStoreError so you can catch them at any level of specificity:
from telestore import (
TeleStoreClient,
TeleStoreError, # base — catches everything below
AuthenticationError, # 401 — bad or missing API key
UploadError, # upload failed
DownloadError, # download failed
FileSizeError, # file exceeds 2 GiB
FileNotFoundError, # file_id not found on server
ServerError, # 5xx from TeleStore
)
client = TeleStoreClient(api_key="sk-...")
try:
result = client.upload("huge_file.iso")
except FileSizeError as exc:
print(f"File too large: {exc}")
except AuthenticationError:
print("Check your API key.")
except UploadError as exc:
print(f"Upload failed: {exc}")
except ServerError as exc:
print(f"TeleStore server error: {exc}")
except TeleStoreError as exc:
# Catch-all for any other library error
print(f"TeleStore error: {exc}")
Note:
telestore.FileNotFoundErrorshadows the Python built-in in this namespace. Import it explicitly by name if you need both in the same scope.
8. File Deletion
Delete files from TeleStore using the delete endpoint:
# Delete a file
client.delete("abc123")
# The file is removed from both Telegram and TeleStore database
9. Advanced Patterns
Retry Logic with Tenacity
from tenacity import retry, stop_after_attempt, wait_exponential
from telestore import TeleStoreClient, TeleStoreError
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
reraise=True
)
def upload_with_retry(client: TeleStoreClient, path: str):
return client.upload(path)
client = TeleStoreClient(api_key="sk-...")
result = upload_with_retry(client, "large_file.iso")
Batch Upload with Progress Tracking
from pathlib import Path
from telestore import TeleStoreClient
client = TeleStoreClient(api_key="sk-...")
files_dir = Path("./documents")
results = []
for i, file_path in enumerate(files_dir.glob("*.pdf"), 1):
print(f"Uploading {i}/{len(list(files_dir.glob('*.pdf')))} — {file_path.name}")
result = client.upload(file_path)
results.append(result)
print(f" ✓ {result.view_url}")
# Save file_id mappings for later retrieval
with open("uploaded_files.txt", "w") as f:
for result in results:
f.write(f"{result.original_filename},{result.file_id}\n")
Monitoring Upload Progress
For real-time progress during large file uploads, implement custom streaming:
import requests
from pathlib import Path
client = TeleStoreClient(api_key="sk-...")
file_path = Path("large_video.mp4")
file_size = file_path.stat().st_size
# Upload with callback
with open(file_path, "rb") as f:
# Implement custom progress tracking here
result = client.upload(f, filename=file_path.name)
Integration with Django
# In a Django view
from django.http import JsonResponse
from telestore import TeleStoreClient, UploadError
def upload_document(request):
if not request.FILES.get('document'):
return JsonResponse({'error': 'No file'}, status=400)
try:
client = TeleStoreClient(api_key=request.user.telestore_api_key)
result = client.upload(request.FILES['document'])
# Save mapping in your database
UserFile.objects.create(
user=request.user,
filename=result.original_filename,
file_id=result.file_id,
size_bytes=result.size_bytes
)
return JsonResponse({
'success': True,
'view_url': result.view_url,
'file_id': result.file_id
})
except UploadError as e:
return JsonResponse({'error': str(e)}, status=400)
Integration with FastAPI
from fastapi import FastAPI, UploadFile, Depends, HTTPException
from telestore import TeleStoreClient
app = FastAPI()
def get_telestore_client() -> TeleStoreClient:
return TeleStoreClient(api_key="sk-...")
@app.post("/upload/")
async def upload_file(
file: UploadFile,
client: TeleStoreClient = Depends(get_telestore_client)
):
try:
content = await file.read()
result = client.upload(content, filename=file.filename)
return {
"file_id": result.file_id,
"view_url": result.view_url,
"download_url": result.download_url
}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
10. Limitations & Known Issues
Current Limitations
- Files larger than 50 MB are uploaded through a slower Telethon MTProto path on the server side, which is significantly slower than the Bot API path. The default 120-second timeout accommodates this, but very large files on slow connections may still time out — increase
timeoutas needed. - View and download URLs are publicly accessible — no authentication required. Anyone who knows a
file_idcan access the file. Treatfile_idvalues as secrets for sensitive content. - No file listing on anonymous access —
list_files()requires authentication. You must trackfile_idvalues yourself if uploading anonymously. - No async support in v0.1 — fully synchronous. Async support (
asyncio/httpx) planned for v0.2. - No built-in retry logic — failed requests raise immediately. Use
tenacityfor automatic retries. python-magicis optional — without it, MIME detection falls back to filename extension, less reliable for binary.
Planned Features
- Async/await support
- Streaming uploads with progress callbacks
- File expiration and TTL
- Signed/time-limited URLs
- Multi-part uploads for large files
- Batch operations
- WebSocket support for real-time updates
11. Troubleshooting
"Invalid or missing API key (HTTP 401)"
Cause: API key not set, empty, or revoked.
Fix:
# Make sure your API key is valid
client = TeleStoreClient(api_key="sk-abc1234...") # Must start with 'sk-'
# Regenerate key at https://telestore.onrender.com/api-keys/
"File size exceeds 2 GB"
Cause: Attempting to upload a file larger than Telegram's limit.
Fix:
# Split large files or use cloud storage instead
from telestore import FileSizeError
try:
result = client.upload("huge_file.iso")
except FileSizeError:
print("Use a different storage backend for files > 2 GB")
"Upload request failed: Connection timeout"
Cause: Server taking too long (slow network or large file via Telethon).
Fix:
# Increase timeout for large files
client = TeleStoreClient(api_key="sk-...", timeout=300) # 5 minutes
"The requested file was not found (HTTP 404)"
Cause: File was deleted or file_id is incorrect.
Fix:
# Verify file_id before download
from telestore import FileNotFoundError
try:
data = client.download("invalid_file_id")
except FileNotFoundError:
print("File has been deleted or never existed")
"python-magic not installed"
Cause: Optional dependency missing.
Fix:
# Install for better MIME detection
pip install python-magic
pip install python-magic-bin # Windows only
12. Performance Tips
- Use
python-magicfor accurate MIME detection — without it, guessing fails for binary files. - Set appropriate timeout — 120s default, but increase for files >100 MB.
- Batch operations — upload multiple files sequentially rather than in parallel (Telegram rate limits).
- Stream large downloads to disk — don't load into memory:
path = client.download("abc123", destination="cache/file.bin")
- Cache
file_idvalues — avoid re-uploading same content. - Use
get_url()for public links — no network call, instant URL generation.
13. Contributing
Contributions are welcome! Please follow these guidelines:
Setting Up Development Environment
git clone <repo-url>
cd Telestore_library_v0.1
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
Running Tests
# Run all tests
pytest tests/
# Run with coverage
pytest --cov=telestore tests/
# Run specific test
pytest tests/test_client.py::test_upload
Code Style
# Format code
black telestore tests
# Lint
flake8 telestore tests
# Type checking
mypy telestore
Submitting Changes
- Create a feature branch:
git checkout -b feature/my-feature - Write tests for new functionality
- Ensure all tests pass:
pytest - Format code:
black . && flake8 . - Commit:
git commit -am "Add my feature" - Push:
git push origin feature/my-feature - Open a pull request with clear description
Requirements for PR acceptance:
- All tests must pass
- Type hints for all new functions
- Docstrings for all public methods
- No breaking changes to existing API
14. API Reference
TeleStoreClient
class TeleStoreClient:
"""
Synchronous HTTP client for TeleStore REST API.
Attributes:
api_key (str): Your TeleStore API key
base_url (str): Server URL
timeout (int): Request timeout in seconds
"""
def __init__(
self,
api_key: str,
base_url: str = "https://telestore.onrender.com",
timeout: int = 120,
) -> None: ...
def upload(
self,
source: Union[str, Path, bytes, IO[bytes]],
filename: Optional[str] = None,
) -> UploadedFile: ...
def download(
self,
file_id: str,
destination: Optional[Union[str, Path]] = None,
) -> Union[bytes, Path]: ...
def delete(self, file_id: str) -> None: ...
def list_files(self, ids_only: bool = False) -> List[Dict]: ...
def list_file_ids(self) -> List[str]: ...
def get_url(self, file_id: str, mode: str = "view") -> str: ...
def url_upload(
self,
url: str,
filename: Optional[str] = None,
) -> UploadedFile: ...
def upload_image(
self,
source: Union[str, Path, bytes, IO[bytes]],
filename: Optional[str] = None,
) -> UploadedFile: ...
def upload_text(
self,
text: str,
filename: str = "file.txt",
encoding: str = "utf-8",
) -> UploadedFile: ...
def upload_json(
self,
data: Dict,
filename: str = "data.json",
) -> UploadedFile: ...
def download_text(
self,
file_id: str,
encoding: str = "utf-8",
) -> str: ...
def download_json(self, file_id: str) -> Dict: ...
UploadedFile
@dataclass
class UploadedFile:
"""
Metadata for a successfully uploaded file.
Attributes:
file_id (str): Opaque file identifier
view_url (str): Inline viewing URL (no auth required)
download_url (str): Download/attachment URL (no auth required)
original_filename (str): Filename used at upload
size_bytes (int): File size in bytes
mime_type (str): Detected MIME type
"""
file_id: str
view_url: str
download_url: str
original_filename: str
size_bytes: int
mime_type: str
Exception Hierarchy
TeleStoreError (base)
├── AuthenticationError # 401, bad/missing API key
├── UploadError # Upload failed
├── DownloadError # Download failed
├── FileSizeError # File > 2 GB
├── FileNotFoundError # 404, file_id not found
└── ServerError # 5xx, server error
15. FAQ
Q: Can I use TeleStore in production?
A: Yes, but it's a self-hosted service. TeleStore is production-ready for small-to-medium workloads. For mission-critical systems, implement backups and redundancy at the server level.
Q: What happens if Telegram deletes/bans my channel?
A: Files become inaccessible. The server tracks this via the is_banned flag on channels. TeleStore includes automatic backup to secondary channels to mitigate this.
Q: Can I encrypt files before uploading?
A: Not built-in, but you can encrypt client-side before calling upload(). Decrypt after downloading.
Q: Is there a quota per user?
A: Not enforced in v0.1. Server admin can implement rate limiting if needed.
Q: Can I run my own TeleStore instance?
A: Yes! Fork the server repository and self-host. See server README for setup.
License
MIT License — see LICENSE for details.
Made with ❤️ for developers who want free file storage
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file telestore-0.1.0.tar.gz.
File metadata
- Download URL: telestore-0.1.0.tar.gz
- Upload date:
- Size: 22.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1ec08e4f6cf3fe53dc0e6a83dda03f5c60882c52b60b8d30ceb84deb6b1a54a
|
|
| MD5 |
a5ee0ca7dc884947eb54ff94ea1b738c
|
|
| BLAKE2b-256 |
5ae8b8aa0c83c2b9b6fd333bf00157c7f0b5bc2fa4ddb2b03a1f864ea1b384c0
|
File details
Details for the file telestore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: telestore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f43f08eb47f33a49466f9a999f3a0be182f1dd34f4c29cd9b75b3fccadfde17f
|
|
| MD5 |
1c66618264611e931545fec35becbed3
|
|
| BLAKE2b-256 |
f27607cc39091bf640b122569f401cb1b64859135ead20f55736b66a95cac2c9
|