Player¶
The Player resource provides access to player profiles, rankings, tournament results, and head-to-head comparisons.
Quick Example¶
from ifpa_api import IfpaClient
from ifpa_api.models.player import PlayerSearchResponse
client: IfpaClient = IfpaClient()
# Fluent query builder - search for players named "Smith" in Idaho
results: PlayerSearchResponse = client.player.query("Smith").state("ID").get()
Search for Players¶
The recommended way to search for players is using the fluent query builder:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PlayerSearchResponse
client: IfpaClient = IfpaClient()
# Simple name search
results: PlayerSearchResponse = client.player.query("Smith").state("ID").get()
for player in results.search:
print(f"{player.player_id}: {player.first_name} {player.last_name}")
print(f" Location: {player.city}, {player.state}")
print(f" Current Rank: #{player.wppr_rank}")
# Output:
# 25584: Dwayne Smith
# Location: Boise, ID
# Current Rank: #753
# 47585: Debbie Smith
# Location: Boise, ID
# Current Rank: #7078
Chained Filters¶
The fluent API allows method chaining for complex queries:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PlayerSearchResponse
client: IfpaClient = IfpaClient()
# Chain multiple filters
results: PlayerSearchResponse = (client.player.query("John")
.country("US")
.state("ID")
.limit(5)
.get())
# Filter by tournament participation
results: PlayerSearchResponse = (client.player.query()
.tournament("PAPA")
.position(1)
.limit(10)
.get())
# Location-only search (no name query)
results: PlayerSearchResponse = (client.player.query()
.country("US")
.state("ID")
.limit(25)
.get())
Query Reuse (Immutable Pattern)¶
The query builder is immutable - each method returns a new instance, allowing query reuse:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PlayerSearchResponse
client: IfpaClient = IfpaClient()
# Create a reusable base query for US players
us_query = client.player.query().country("US")
# Derive state-specific queries from the base
wa_players: PlayerSearchResponse = us_query.state("WA").limit(25).get()
id_players: PlayerSearchResponse = us_query.state("ID").limit(25).get()
or_players: PlayerSearchResponse = us_query.state("OR").limit(25).get()
# The base query remains unchanged and can be reused
ca_players: PlayerSearchResponse = us_query.state("CA").limit(25).get()
Query Builder Methods¶
| Method | Parameter | Description |
|---|---|---|
.query(name) |
str |
Player name (partial match, case insensitive) |
.state(code) |
str |
State/province code (2-digit, e.g., "ID", "WA") |
.country(code) |
str |
Country name or 2-digit code (e.g., "US", "CA") |
.tournament(name) |
str |
Tournament name (partial strings accepted) |
.position(pos) |
int |
Finishing position in tournament |
.offset(start) |
int |
Pagination offset (0-based) |
.limit(count) |
int |
Maximum number of results |
.get() |
- | Execute query and return results |
API Pagination Limitations
The IFPA API's player search pagination is currently non-functional. Using .offset() may cause
errors or return 0 results. For best results, use only .limit() and avoid .offset().
Migration from 0.2.x
The client.player.search(name="John") method was removed in v0.3.0.
Use the fluent query builder instead: client.player.query("John").get()
Get Player Profile¶
Retrieve detailed information about a specific player:
from ifpa_api import IfpaClient
from ifpa_api.models.player import Player
client: IfpaClient = IfpaClient()
# Get player by ID - Dwayne Smith (highly active player from Boise, ID)
player: Player = client.player(25584).details()
print(f"Name: {player.first_name} {player.last_name}")
print(f"Location: {player.city}, {player.stateprov}, {player.country_name}")
print(f"Player ID: {player.player_id}")
print(f"IFPA Registered: {player.ifpa_registered}")
print(f"Age: {player.age}")
# Access rankings across systems
for ranking in player.rankings:
print(f"{ranking.ranking_system}: Rank {ranking.rank}, Rating {ranking.rating}")
# Output:
# Name: Dwayne Smith
# Location: Boise, ID, United States
# Player ID: 25584
# IFPA Registered: True
# Age: 55
# Main: Rank 753, Rating 65.42
Profile Information¶
Player profiles include:
- Identity: Name, location, player ID, initials
- Rankings: List of rankings across different systems (Main, Women, Youth, etc.)
- Registration: Age, IFPA membership status, FIDE player status
- Statistics: Additional player statistics in
player_statsdictionary - Profile: Profile photo URL, exclusion flag
Invalid Player IDs¶
When requesting a non-existent player, the SDK raises an error:
from ifpa_api import IfpaClient
from ifpa_api.core.exceptions import IfpaApiError
client: IfpaClient = IfpaClient()
try:
player = client.player(99999999).details()
except IfpaApiError as e:
if e.status_code == 404:
print("Player not found")
Tournament Results¶
Get a player's tournament history:
from ifpa_api import IfpaClient
from ifpa_api.models.common import RankingSystem, ResultType
from ifpa_api.models.player import PlayerResultsResponse
client: IfpaClient = IfpaClient()
# Get all active results for Dwayne Smith (both parameters required)
results: PlayerResultsResponse = client.player(25584).results(
ranking_system=RankingSystem.MAIN,
result_type=ResultType.ACTIVE
)
print(f"Total results: {results.total_results}")
for result in results.results[:3]: # Show first 3 results
print(f"\n{result.tournament_name}")
print(f" Date: {result.event_date}")
print(f" Position: {result.position} of {result.player_count}")
print(f" WPPR Points: {result.current_points}")
print(f" Rating: {result.rating_value}")
# Output:
# Total results: 218
#
# Thursday night pinball
# Date: 2024-12-05
# Position: 4 of 11
# WPPR Points: 3.49
# Rating: 8.36
Filter Results¶
Both ranking_system and result_type are required parameters:
from ifpa_api import IfpaClient
from ifpa_api.models.common import RankingSystem, ResultType
from ifpa_api.models.player import PlayerResultsResponse
client: IfpaClient = IfpaClient()
# Main ranking active results for Dwayne Smith
active: PlayerResultsResponse = client.player(25584).results(
ranking_system=RankingSystem.MAIN,
result_type=ResultType.ACTIVE
)
# Women's ranking active results for Debbie Smith
women: PlayerResultsResponse = client.player(47585).results(
ranking_system=RankingSystem.WOMEN,
result_type=ResultType.ACTIVE
)
# All inactive results for Dwayne Smith
inactive: PlayerResultsResponse = client.player(25584).results(
ranking_system=RankingSystem.MAIN,
result_type=ResultType.INACTIVE
)
Pagination Not Supported
While the API accepts start_pos and count parameters for results, they are currently
ignored by the API. Requesting a specific page size or offset will not work as expected.
The API returns all results regardless of these parameters.
Ranking Systems¶
RankingSystem.MAIN- Main WPPR rankingsRankingSystem.WOMEN- Women's rankingsRankingSystem.YOUTH- Youth rankingsRankingSystem.PRO- Pro circuit rankings
Result Types¶
ResultType.ACTIVE- Currently active results counting toward rankingsResultType.NONACTIVE- Non-active resultsResultType.INACTIVE- Inactive results not counting toward rankings
Head-to-Head Comparison¶
Compare two players' tournament history:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PvpComparison
from ifpa_api.core.exceptions import PlayersNeverMetError
client: IfpaClient = IfpaClient()
try:
# Compare Dwayne Smith vs Debbie Smith (they've played 205 tournaments together)
pvp: PvpComparison = client.player(25584).pvp(47585)
print(f"Player 1: {pvp.player1_name}")
print(f"Player 2: {pvp.player2_name}")
print(f"\nHead-to-Head Record:")
print(f" {pvp.player1_name} wins: {pvp.player1_wins}")
print(f" {pvp.player2_name} wins: {pvp.player2_wins}")
print(f" Ties: {pvp.ties}")
print(f" Total meetings: {pvp.total_meetings}")
# Show tournament-by-tournament breakdown (first 3)
for match in pvp.tournaments[:3]:
winner = "Player 1" if match.winner_player_id == pvp.player1_id else "Player 2"
print(f"\n{match.tournament_name} ({match.event_date})")
print(f" {pvp.player1_name}: Position {match.player_1_position}")
print(f" {pvp.player2_name}: Position {match.player_2_position}")
print(f" Winner: {winner}")
except PlayersNeverMetError:
print("These players have never competed in the same tournament")
# Output:
# Player 1: Dwayne Smith
# Player 2: Debbie Smith
#
# Head-to-Head Record:
# Dwayne Smith wins: 139
# Debbie Smith wins: 66
# Ties: 0
# Total meetings: 205
Exception Handling¶
The pvp() method raises PlayersNeverMetError when two players have never competed together:
from ifpa_api import IfpaClient
from ifpa_api.core.exceptions import PlayersNeverMetError, IfpaApiError
client: IfpaClient = IfpaClient()
try:
# John Sosoka (50104) vs World #1 player (1) - they've never met
comparison = client.player(50104).pvp(1)
except PlayersNeverMetError as e:
print(f"Players {e.player_id} and {e.opponent_id} have never met")
except IfpaApiError as e:
print(f"API error: {e}")
# Output:
# Players 50104 and 1 have never met
PvP All Competitors¶
Get a summary of all players a player has competed against:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PvpAllCompetitors
client: IfpaClient = IfpaClient()
# Get summary of all competitors for Dwayne Smith
summary: PvpAllCompetitors = client.player(25584).pvp_all()
print(f"Player ID: {summary.player_id}")
print(f"Total competitors: {summary.total_competitors}")
print(f"System: {summary.system}")
print(f"Type: {summary.type}")
# Output:
# Player ID: 25584
# Total competitors: 375
# System: MAIN
# Type: all
Ranking History¶
Track a player's WPPR ranking and rating over time:
from ifpa_api import IfpaClient
from ifpa_api.models.player import RankingHistory
client: IfpaClient = IfpaClient()
# Get ranking history for Dwayne Smith
history: RankingHistory = client.player(25584).history()
print(f"Player ID: {history.player_id}")
print(f"System: {history.system}")
print(f"Active: {history.active_flag}")
print("\nRank History (last 5):")
for entry in history.rank_history[-5:]:
print(f"{entry.rank_date}: Rank #{entry.rank_position}, "
f"WPPR {entry.wppr_points}, "
f"Tournaments: {entry.tournaments_played_count}")
print("\nRating History (last 5):")
for entry in history.rating_history[-5:]:
print(f"{entry.rating_date}: Rating {entry.rating}")
# Output:
# Player ID: 25584
# System: MAIN
# Active: Y
#
# Rank History (last 5):
# 2024-11-01: Rank #765, WPPR 65.25, Tournaments: 432
# 2024-12-01: Rank #753, WPPR 65.42, Tournaments: 433
String Values
The API returns numeric fields as strings in history data. Convert them using int() or
float() when performing calculations.
Complete Example: Player Analysis¶
Here's a complete example that analyzes a player's profile:
from ifpa_api import IfpaClient
from ifpa_api.core.exceptions import IfpaApiError
from ifpa_api.models.common import RankingSystem, ResultType
from ifpa_api.models.player import Player, PlayerResultsResponse, RankingHistory
def analyze_player(player_id: int = 25584) -> None:
"""Comprehensive player analysis.
Default player: Dwayne Smith (25584) - highly active player from Boise, ID
"""
client: IfpaClient = IfpaClient()
try:
# Get player profile
player: Player = client.player(player_id).details()
print("=" * 60)
print(f"{player.first_name} {player.last_name}")
print("=" * 60)
# Basic info
print(f"\nLocation: {player.city}, {player.stateprov}, {player.country_name}")
print(f"Player ID: {player.player_id}")
print(f"Age: {player.age}")
print(f"IFPA Registered: {player.ifpa_registered}")
# Rankings across systems
print(f"\nRankings by System:")
for ranking in player.rankings:
print(f" {ranking.ranking_system}: Rank {ranking.rank}, Rating {ranking.rating}")
if ranking.country_rank:
print(f" Country Rank: {ranking.country_rank}")
# Recent results
print(f"\nRecent Tournament Results:")
results: PlayerResultsResponse = client.player(player_id).results(
ranking_system=RankingSystem.MAIN,
result_type=ResultType.ACTIVE
)
for result in results.results[:5]:
finish = f"{result.position}/{result.player_count}" if result.player_count else str(result.position)
points = f"{result.current_points:.2f}" if result.current_points else "N/A"
print(f" {result.tournament_name}: {finish} ({points} pts)")
# Ranking trend
history: RankingHistory = client.player(player_id).history()
if len(history.rank_history) >= 2:
recent = history.rank_history[-1]
previous = history.rank_history[-2]
rank_change = int(previous.rank_position) - int(recent.rank_position)
rating_change = float(recent.wppr_points) - float(previous.wppr_points)
print(f"\nRecent Trend:")
print(f" Rank change: {rank_change:+d}")
print(f" WPPR change: {rating_change:+.2f}")
except IfpaApiError as e:
print(f"API Error: {e}")
if e.status_code:
print(f"Status Code: {e.status_code}")
if __name__ == "__main__":
# Analyze Dwayne Smith - highly active player
analyze_player(25584)
Best Practices¶
Error Handling¶
Always handle potential errors:
from ifpa_api import IfpaClient
from ifpa_api.core.exceptions import IfpaApiError
from ifpa_api.models.player import Player
client: IfpaClient = IfpaClient()
try:
player: Player = client.player(99999999).details()
except IfpaApiError as e:
if e.status_code == 404:
print("Player not found")
else:
print(f"API error: {e}")
Caching Results¶
For frequently accessed data, consider caching:
from functools import lru_cache
from ifpa_api import IfpaClient
from ifpa_api.models.player import Player
@lru_cache(maxsize=100)
def get_cached_player(player_id: int) -> Player:
"""Get player with caching."""
client: IfpaClient = IfpaClient()
return client.player(player_id).details()
# First call fetches from API
player: Player = get_cached_player(25584) # Dwayne Smith
# Subsequent calls use cache
player: Player = get_cached_player(25584) # Instant - from cache
Reusable Queries¶
Take advantage of the immutable query builder pattern:
from ifpa_api import IfpaClient
from ifpa_api.models.player import PlayerSearchResponse
client: IfpaClient = IfpaClient()
# Create a base query for tournament winners
winners_query = client.player.query().position(1)
# Derive specific tournament queries
papa_winners: PlayerSearchResponse = winners_query.tournament("PAPA").limit(10).get()
pinburgh_winners: PlayerSearchResponse = winners_query.tournament("Pinburgh").limit(10).get()
tilt_winners: PlayerSearchResponse = winners_query.tournament("TILT").limit(10).get()
Known Limitations¶
API Pagination Issues¶
The IFPA API has several known pagination issues:
- Player Search Pagination: Using
.offset()may cause SQL errors or return 0 results - Results Pagination: The
countandstart_posparameters are ignored by the API - State/Province Filter: May return players from incorrect states/countries
These are API-level issues, not SDK bugs. For the most reliable experience:
- Avoid using
.offset()in player searches - Don't rely on pagination for player results
- Be cautious with state/province filters - verify results manually
Migration from 0.2.x¶
Migration from 0.2.x
The search() method was removed in v0.3.0. Use the fluent query builder instead:
# Old (0.2.x):
results: PlayerSearchResponse = client.player.search(name="Smith", stateprov="ID")
# New (0.3.0+):
results: PlayerSearchResponse = client.player.query("Smith").state("ID").get()
The query builder is immutable and chainable, enabling query reuse and better type safety.
Related Resources¶
- Rankings - View rankings across all players
- Tournaments - View tournament results
- Error Handling - Handle API errors
- Exceptions Reference - Exception types