A Python client library for the CryptoPanic API
Project description
cryptopanic
A modern, type-safe Python client library for the CryptoPanic API. This library provides a clean, intuitive interface to access cryptocurrency news and market data.
Features
- 🚀 Type-safe: Built with Pydantic for robust data validation
- 🎯 Easy to use: Simple, Pythonic API design
- 🔒 Error handling: Comprehensive exception handling for all API error codes
- 📦 Well tested: High test coverage with pytest
- 🛠️ Developer friendly: Full type hints, comprehensive documentation
- ⚡ Async ready: Built on requests for reliable HTTP handling
Installation
pip install cryptopanic
Quick Start
from cryptopanic import CryptoPanicClient
# Initialize the client with your API token
client = CryptoPanicClient(auth_token="your_api_token_here")
# Get news posts for Bitcoin and Ethereum
posts = client.get_posts(
currencies=["BTC", "ETH"],
filter="rising"
)
# Iterate through posts
for post in posts.results:
print(f"{post.title} - {post.published_at}")
print(f"Source: {post.source.title}")
print(f"URL: {post.url}")
print(f"Panic Score: {post.panic_score}")
print("-" * 50)
API Reference
CryptoPanicClient
The main client class for interacting with the CryptoPanic API.
Initialization
client = CryptoPanicClient(
auth_token: str, # Your CryptoPanic API token (required)
timeout: int = 30 # Request timeout in seconds (optional)
)
Methods
get_posts(...)
Retrieve a list of news posts with various filtering options.
Parameters:
public(bool, optional): Enable public mode (uses non-user-specific settings)currencies(list[str], optional): Filter by currency codes (e.g.,["BTC", "ETH"])regions(list[str], optional): Filter by regions (e.g.,["en", "fr"])filter(str, optional): Filter by type:"rising","hot","bullish","bearish","important","saved","lol"kind(str, optional): Filter by news kind:"news","media","all"(default:"all")following(bool, optional): Filter by sources you follow (PRIVATE API only)last_pull(datetime | str, optional): Limit search to last pull time (ISO 8601) - Enterprise onlypanic_period(str, optional): Include panic score for period:"1h","6h","24h"- Enterprise onlypanic_sort(str, optional): Sort by panic score:"asc"or"desc"(requirespanic_period) - Enterprise onlysize(int, optional): Items per page (1-500, max 500) - Enterprise onlywith_content(bool, optional): Filter items with full content - Enterprise onlysearch(str, optional): Search by keyword - Enterprise onlyformat(str, optional): Response format (e.g.,"rss") - returns max 20 items
Returns: PostsResponse object containing:
results: List ofPostobjectsnext: URL for next page (orNone)previous: URL for previous page (orNone)
Example:
# Get rising news for Bitcoin
posts = client.get_posts(
currencies=["BTC"],
filter="rising"
)
# Get public news in English and French
posts = client.get_posts(
public=True,
regions=["en", "fr"]
)
# Search for specific keywords (Enterprise plan)
posts = client.get_posts(
search="bitcoin halving"
)
get_portfolio()
Retrieve your portfolio. Available only for GROWTH and ENTERPRISE API plans.
Returns: PortfolioResponse object
Example:
portfolio = client.get_portfolio()
Data Models
Post
Represents a news post from CryptoPanic.
class Post:
id: int
slug: str
title: str
description: str
published_at: datetime
created_at: datetime
kind: str # "news", "media", "blog", "twitter", "reddit"
source: Source
original_url: str
url: str
image: str | None
instruments: list[Instrument]
votes: Votes
panic_score: int | None # 0-100
panic_score_1h: int | None # 0-100
author: str | None
content: Content | None
Instrument
Represents a cryptocurrency instrument.
class Instrument:
code: str # e.g., "BTC"
title: str # e.g., "Bitcoin"
slug: str
url: str
market_cap_usd: float | None
price_in_usd: float | None
price_in_btc: float | None
price_in_eth: float | None
price_in_eur: float | None
market_rank: int | None
Source
Represents a news source.
class Source:
title: str
region: str # Language code (e.g., "en", "fr")
domain: str
type: str # "feed", "blog", "twitter", "media", "reddit"
Votes
Represents vote counts for a post.
class Votes:
negative: int
positive: int
important: int
liked: int
disliked: int
lol: int
toxic: int
saved: int
comments: int
Error Handling
The library provides specific exception classes for different error scenarios:
from cryptopanic import (
CryptoPanicClient,
CryptoPanicAuthenticationError,
CryptoPanicForbiddenError,
CryptoPanicRateLimitError,
CryptoPanicServerError,
CryptoPanicAPIError,
)
client = CryptoPanicClient(auth_token="your_token")
try:
posts = client.get_posts()
except CryptoPanicAuthenticationError:
print("Invalid API token")
except CryptoPanicRateLimitError:
print("Rate limit exceeded. Please wait before making more requests.")
except CryptoPanicForbiddenError:
print("Access forbidden. Check your API plan limits.")
except CryptoPanicServerError:
print("Server error. Please try again later.")
except CryptoPanicAPIError as e:
print(f"API error: {e}")
Exception Classes
CryptoPanicAPIError: Base exception for all API errorsCryptoPanicAuthenticationError: Raised on 401 UnauthorizedCryptoPanicForbiddenError: Raised on 403 Forbidden (rate limit or access denied)CryptoPanicRateLimitError: Raised on 429 Too Many RequestsCryptoPanicServerError: Raised on 500 Internal Server Error
Examples
Filter by Multiple Currencies
posts = client.get_posts(
currencies=["BTC", "ETH", "SOL"],
filter="hot"
)
for post in posts.results:
print(f"{post.title}")
for instrument in post.instruments:
print(f" - {instrument.code}: ${instrument.price_in_usd}")
Get Posts with Full Content
# Enterprise plan only
posts = client.get_posts(
currencies=["BTC"],
with_content=True
)
for post in posts.results:
if post.content:
print(f"Title: {post.title}")
print(f"Clean content: {post.content.clean}")
Pagination
posts = client.get_posts(currencies=["BTC"])
# Process first page
for post in posts.results:
print(post.title)
# Get next page (you would need to parse the URL or implement pagination helper)
if posts.next:
print(f"Next page: {posts.next}")
RSS Feed
# Get RSS feed (max 20 items)
posts = client.get_posts(
currencies=["BTC"],
format="rss"
)
Development
Setup
# Clone the repository
git clone https://github.com/guilyx/cryptopanic.git
cd cryptopanic
# Install in development mode
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install
Running Tests
# Run all tests (unit tests only, uses mocked requests)
pytest
# Run with coverage
pytest --cov=cryptopanic --cov-report=html
# Run specific test file
pytest tests/test_client.py
# Run integration tests (requires CRYPTOPANIC_AUTH_TOKEN env var)
CRYPTOPANIC_AUTH_TOKEN=your_token pytest tests/test_integration.py
# Run all tests including integration tests
CRYPTOPANIC_AUTH_TOKEN=your_token pytest
Note: Unit tests use mocked API responses and don't require a real API token. Integration tests make real API calls and require the CRYPTOPANIC_AUTH_TOKEN environment variable to be set.
Code Quality
# Format code
black .
# Lint code
ruff check .
# Type checking
mypy cryptopanic
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass and code is formatted
- Commit your changes (following the commit message guidelines)
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- CryptoPanic for providing the API
- All contributors who help improve this library
Release Process
Development Flow
- Feature Development: Work happens on feature branches
- Merge to Master: Features are merged to
masterafter review - Release Candidates: When enough features accumulate (typically 3-5), create a release candidate:
# Update version in pyproject.toml (e.g., 0.2.0rc1) git add pyproject.toml CHANGELOG.md git commit -m "chore: prepare release 0.2.0rc1" git tag v0.2.0rc1 git push origin master --tags
- Optional: Create a GitHub Release marked as "pre-release" for testing (won't publish to PyPI)
- Test: Install and test the release candidate:
pip install cryptopanic==0.2.0rc1
- Final Release: After testing passes, create final release:
# Update version in pyproject.toml (e.g., 0.2.0) git add pyproject.toml CHANGELOG.md git commit -m "chore: release 0.2.0" git tag v0.2.0 git push origin master --tags
- GitHub Release: Create a GitHub Release with the tag (via UI or
gh release create v0.2.0) - Auto-publish: Workflow automatically publishes final releases to PyPI (pre-releases are skipped)
Setup (One-time)
PyPI Trusted Publishing:
- Create GitHub Environment: Settings → Environments → New (
pypi) - Configure at https://pypi.org/manage/account/publishing/:
- Project:
cryptopanic - Workflow:
publish.yml - Environment:
pypi - Repository:
guilyx/cryptopanic
- Project:
Version Format: Follow Semantic Versioning (MAJOR.MINOR.PATCH)
Support
For issues, questions, or contributions, please open an issue on GitHub.
Changelog
See CHANGELOG.md for detailed release notes.
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 cryptopanic-0.1.0.tar.gz.
File metadata
- Download URL: cryptopanic-0.1.0.tar.gz
- Upload date:
- Size: 19.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0cb0ee38b7a213f3571c313be8af69d253301454b1b14ca99e2fca3d599b3b3b
|
|
| MD5 |
2a54b42723454d81a5a2939baea7e7f8
|
|
| BLAKE2b-256 |
e3491d34c757281652a391e5a7fa1c3847a62a4797a9d13637cd9f01cfb9c6d8
|
Provenance
The following attestation bundles were made for cryptopanic-0.1.0.tar.gz:
Publisher:
publish.yml on guilyx/cryptopanic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cryptopanic-0.1.0.tar.gz -
Subject digest:
0cb0ee38b7a213f3571c313be8af69d253301454b1b14ca99e2fca3d599b3b3b - Sigstore transparency entry: 803880109
- Sigstore integration time:
-
Permalink:
guilyx/cryptopanic@c8e0ce25b2eb6db85871ee39c63a9cfc7aee6294 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/guilyx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c8e0ce25b2eb6db85871ee39c63a9cfc7aee6294 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cryptopanic-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cryptopanic-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6cc116954c46b4e34e6265fc36bc221423b0d516fccf850468f535337b80c43
|
|
| MD5 |
539e923e6533d0d3a0b50a2046ec20dd
|
|
| BLAKE2b-256 |
778583a2dfade6470d5f1f5af3965e4110398d96165ab364d5d458ab432329e3
|
Provenance
The following attestation bundles were made for cryptopanic-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on guilyx/cryptopanic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cryptopanic-0.1.0-py3-none-any.whl -
Subject digest:
a6cc116954c46b4e34e6265fc36bc221423b0d516fccf850468f535337b80c43 - Sigstore transparency entry: 803880113
- Sigstore integration time:
-
Permalink:
guilyx/cryptopanic@c8e0ce25b2eb6db85871ee39c63a9cfc7aee6294 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/guilyx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c8e0ce25b2eb6db85871ee39c63a9cfc7aee6294 -
Trigger Event:
release
-
Statement type: