Skip to main content

A Python client library for the CryptoPanic API

Project description

cryptopanic

Unit Tests Integration Tests codecov PyPI version Python 3.10+ License: MIT Code style: black Ruff

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 only
  • panic_period (str, optional): Include panic score for period: "1h", "6h", "24h" - Enterprise only
  • panic_sort (str, optional): Sort by panic score: "asc" or "desc" (requires panic_period) - Enterprise only
  • size (int, optional): Items per page (1-500, max 500) - Enterprise only
  • with_content (bool, optional): Filter items with full content - Enterprise only
  • search (str, optional): Search by keyword - Enterprise only
  • format (str, optional): Response format (e.g., "rss") - returns max 20 items

Returns: PostsResponse object containing:

  • results: List of Post objects
  • next: URL for next page (or None)
  • previous: URL for previous page (or None)

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 errors
  • CryptoPanicAuthenticationError: Raised on 401 Unauthorized
  • CryptoPanicForbiddenError: Raised on 403 Forbidden (rate limit or access denied)
  • CryptoPanicRateLimitError: Raised on 429 Too Many Requests
  • CryptoPanicServerError: 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass and code is formatted
  6. Commit your changes (following the commit message guidelines)
  7. Push to the branch (git push origin feature/amazing-feature)
  8. 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

  1. Feature Development: Work happens on feature branches
  2. Merge to Master: Features are merged to master after review
  3. 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
  4. 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
    
  5. GitHub Release: Create a GitHub Release with the tag (via UI or gh release create v0.2.0)
  6. Auto-publish: Workflow automatically publishes final releases to PyPI (pre-releases are skipped)

Setup (One-time)

PyPI Trusted Publishing:

  1. Create GitHub Environment: Settings → Environments → New (pypi)
  2. Configure at https://pypi.org/manage/account/publishing/:
    • Project: cryptopanic
    • Workflow: publish.yml
    • Environment: pypi
    • Repository: guilyx/cryptopanic

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cryptopanic-0.1.0.tar.gz (19.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cryptopanic-0.1.0-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

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

Hashes for cryptopanic-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0cb0ee38b7a213f3571c313be8af69d253301454b1b14ca99e2fca3d599b3b3b
MD5 2a54b42723454d81a5a2939baea7e7f8
BLAKE2b-256 e3491d34c757281652a391e5a7fa1c3847a62a4797a9d13637cd9f01cfb9c6d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for cryptopanic-0.1.0.tar.gz:

Publisher: publish.yml on guilyx/cryptopanic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for cryptopanic-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a6cc116954c46b4e34e6265fc36bc221423b0d516fccf850468f535337b80c43
MD5 539e923e6533d0d3a0b50a2046ec20dd
BLAKE2b-256 778583a2dfade6470d5f1f5af3965e4110398d96165ab364d5d458ab432329e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for cryptopanic-0.1.0-py3-none-any.whl:

Publisher: publish.yml on guilyx/cryptopanic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page