Skip to main content

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.

Acknowledgments

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

Metadata

Release files for python-opendota-sdk 7.40.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-opendota-sdk 7.40.3
File Size Uploaded Provenance Actions
python_opendota_sdk-7.40.3.tar.gz 53.5 kB With provenance Details for python_opendota_sdk-7.40.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for python-opendota-sdk 7.40.3
File Interpreter ABI Platform Actions
python_opendota_sdk-7.40.3-py3-none-any.whl Python 3 none any Details for python_opendota_sdk-7.40.3-py3-none-any.whl

Total release size: 76.3 kB

Release files / python_opendota_sdk-7.40.3.tar.gz

Download URL python_opendota_sdk-7.40.3.tar.gz
Size 53.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e5e292e6bdccf2ec2e3231003720684c949ef9633efe26db78bea0680fa56302
BLAKE2b-256 checksum
How to use checksums
5fca031b29cb745baf41f0f18d51f07766807d62f512d5a5aaae002a1e2e82f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 30, 2025.

Transparency log

Release files / python_opendota_sdk-7.40.3-py3-none-any.whl

Download URL python_opendota_sdk-7.40.3-py3-none-any.whl
Size 22.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb904f7da4b389dbcd94982b64683064a88c6dad220693f08e821dc75907fbef
BLAKE2b-256 checksum
How to use checksums
204eac14d9f02a035607cfd65be869b25c12713b3d170789e924335cea5fb495
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 30, 2025.

Transparency log

Security for python-opendota-sdk 7.40.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for python_opendota_sdk-7.40.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 30, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page