Skip to main content

Modern async Python wrapper for the OpenDota API with full type support

Project description

Python OpenDota SDK

PyPI version Documentation Build Status License: MIT Python 3.9+

A modern, async Python wrapper for the OpenDota API with full type safety and comprehensive coverage.

Features

  • Async/await support - Built with httpx for modern async Python applications
  • Type safety - Full type hints and Pydantic models for all API responses
  • Comprehensive coverage - Support for matches, players, heroes, and more endpoints
  • Rate limiting aware - Handles API rate limits gracefully with proper error handling
  • Simple API - Clean, intuitive interface following Python best practices
  • Well tested - Comprehensive test suite with real API integration tests
  • Python 3.9+ - Compatible with modern Python versions

Installation

pip install python-opendota-sdk

Or with uv:

uv add python-opendota-sdk

Quick Start

import asyncio
from opendota import OpenDota

async def main():
    async with OpenDota() as client:
        # Get recent public matches
        matches = await client.get_public_matches()
        print(f"Found {len(matches)} recent matches")

        # Get detailed match data
        match = await client.get_match(matches[0].match_id)
        print(f"Duration: {match.duration // 60}m {match.duration % 60}s")
        print(f"Winner: {'Radiant' if match.radiant_win else 'Dire'}")

        # Get all heroes
        heroes = await client.get_heroes()
        print(f"Total heroes: {len(heroes)}")

asyncio.run(main())

Authentication

The OpenDota API supports optional API keys for higher rate limits:

# Option 1: Environment variable
export OPENDOTA_API_KEY="your-api-key"

# Option 2: Direct initialization
client = OpenDota(api_key="your-api-key")

Rate Limits:

  • Free tier: 2,000 calls/day, 60 calls/minute
  • With API key: Unlimited calls, higher rate limits

Output Formats

Choose between structured Pydantic models or raw JSON dictionaries:

# Pydantic models (default) - Full type safety
client = OpenDota(format='pydantic')
matches = await client.get_public_matches()
print(matches[0].match_id)  # Type-safe access

# JSON dictionaries - Direct API response
client = OpenDota(format='json')
matches = await client.get_public_matches()
print(matches[0]['match_id'])  # Dict access

API Reference

Matches

async with OpenDota() as client:
    # Get detailed match data
    match = await client.get_match(8461956309)

    # Get recent public matches with MMR filter
    high_mmr = await client.get_public_matches(mmr_ascending=4000)

    # Get professional matches
    pro_matches = await client.get_pro_matches()

Players

async with OpenDota() as client:
    # Get player profile
    player = await client.get_player(70388657)
    print(f"Player: {player.profile.personaname}")
    print(f"Rank: {player.rank_tier}")

    # Get player matches with filters
    pudge_matches = await client.get_player_matches(
        account_id=70388657,
        hero_id=14,  # Pudge
        limit=10,
        win=1  # Only wins
    )

Heroes

async with OpenDota() as client:
    # Get all heroes
    heroes = await client.get_heroes()

    # Get hero statistics
    hero_stats = await client.get_hero_stats()
    for hero in hero_stats[:5]:
        if hero.pro_pick:
            winrate = hero.pro_win / hero.pro_pick * 100
            print(f"{hero.localized_name}: {winrate:.1f}% WR")

Teams

async with OpenDota() as client:
    # Get all teams
    teams = await client.get_teams()
    print(f"Total teams: {len(teams)}")

    # Get specific team details
    team = await client.get_team(8599101)  # Team Spirit
    print(f"{team['name']}: {team['rating']} rating")

    # Get team roster
    players = await client.get_team_players(8599101)
    for player in players[:5]:
        print(f"  {player['name']}: {player['games_played']} games")

    # Get team match history
    matches = await client.get_team_matches(8599101, limit=10)

Pro Players

async with OpenDota() as client:
    # Get all professional players
    pro_players = await client.get_pro_players()
    print(f"Total pro players: {len(pro_players)}")

    # Filter by team
    spirit_players = [p for p in pro_players if p.get('team_id') == 8599101]

Leagues

async with OpenDota() as client:
    # Get all leagues/tournaments
    leagues = await client.get_leagues()
    premium = [l for l in leagues if l.get('tier') == 'premium']

    # Get league details
    league = await client.get_league(15728)  # TI

    # Get league matches
    matches = await client.get_league_matches(15728, limit=50)

    # Get teams in a league
    teams = await client.get_league_teams(15728)

Available Endpoints

Category Method Description
Matches get_match(match_id) Get detailed match data
get_public_matches(**filters) Get public matches
get_pro_matches(**filters) Get professional matches
get_parsed_matches(**filters) Get parsed match data
Players get_player(account_id) Get player profile
get_player_matches(account_id, **filters) Get player match history
Heroes get_heroes() Get all heroes data
get_hero_stats() Get hero statistics
Teams get_teams() Get all teams
get_team(team_id) Get team details
get_team_players(team_id) Get team roster
get_team_matches(team_id, limit) Get team match history
Pro Players get_pro_players() Get all professional players
Leagues get_leagues() Get all leagues/tournaments
get_league(league_id) Get league details
get_league_matches(league_id, limit) Get league matches
get_league_teams(league_id) Get teams in a league

Error Handling

from opendota.exceptions import (
    OpenDotaAPIError,
    OpenDotaNotFoundError,
    OpenDotaRateLimitError
)

try:
    match = await client.get_match(invalid_id)
except OpenDotaNotFoundError:
    print("Match not found")
except OpenDotaRateLimitError:
    print("Rate limit exceeded")
except OpenDotaAPIError as e:
    print(f"API error: {e}")

Development

# Clone the repository
git clone https://github.com/DeepBlueCoding/python-opendota-sdk.git
cd python-opendota-sdk

# Install with development dependencies
uv sync --group dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=opendota

# Type checking
uv run mypy src/

# Linting
uv run ruff check src/ tests/

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Links

Acknowledgments

  • OpenDota for providing the excellent free API
  • httpx for the async HTTP client
  • Pydantic for data validation and parsing

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

python_opendota_sdk-7.39.5.2.tar.gz (38.3 kB view details)

Uploaded Source

Built Distribution

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

python_opendota_sdk-7.39.5.2-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file python_opendota_sdk-7.39.5.2.tar.gz.

File metadata

  • Download URL: python_opendota_sdk-7.39.5.2.tar.gz
  • Upload date:
  • Size: 38.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_opendota_sdk-7.39.5.2.tar.gz
Algorithm Hash digest
SHA256 4a74b236f7a7d6d8c5826f9a5ca515fa6e7336e961ff4c20a972508a76b63dcd
MD5 e3fd6dea871b9191f56554471aee45b6
BLAKE2b-256 aa5790f5e53b3c0db06f2a5bb9da01965b53cca0d1597872b143af2e3ab3ea57

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_opendota_sdk-7.39.5.2.tar.gz:

Publisher: publish.yml on DeepBlueCoding/python-opendota-sdk

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

File details

Details for the file python_opendota_sdk-7.39.5.2-py3-none-any.whl.

File metadata

File hashes

Hashes for python_opendota_sdk-7.39.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0e3c2a4092540d2a81bddf2920edcf5e6a3b5831b10050f5271938fc944c6484
MD5 37061d91c099e3f5b0a265598cf7db85
BLAKE2b-256 62b786869906640a9e8e15f95bb02647ac19a8ec4a63a0516fa9430c4389077e

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_opendota_sdk-7.39.5.2-py3-none-any.whl:

Publisher: publish.yml on DeepBlueCoding/python-opendota-sdk

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