Common Patterns¶
Common usage patterns and best practices for Edgework.
Initialization Patterns¶
Basic Client Setup¶
from edgework import Edgework
# Standard initialization
client = Edgework()
# With custom user agent for your application
client = Edgework(user_agent="MyHockeyApp/1.0")
Error Handling Setup¶
from edgework import Edgework
def create_client():
"""Create client with error handling."""
try:
client = Edgework()
# Test the connection with a simple call
client.players(active_only=True)
return client
except Exception as e:
print(f"Failed to initialize client: {e}")
return None
client = create_client()
if client:
print("Client initialized successfully")
Data Retrieval Patterns¶
Pagination and Limiting¶
# Get data in chunks to avoid large responses
def get_all_players_chunked(client, chunk_size=100):
"""Get all players in manageable chunks."""
all_players = []
offset = 0
while True:
# Note: Actual pagination depends on API support
chunk = client.players(active_only=True)
if not chunk:
break
all_players.extend(chunk)
break # For now, API doesn't support pagination
return all_players
Caching Results¶
from functools import lru_cache
from edgework import Edgework
class CachedEdgework:
def __init__(self):
self.client = Edgework()
@lru_cache(maxsize=128)
def get_team_stats_cached(self, season):
"""Cache team stats to avoid repeated API calls."""
return tuple(self.client.team_stats(season=season))
@lru_cache(maxsize=128)
def get_players_cached(self, active_only=True):
"""Cache player list."""
return tuple(self.client.players(active_only=active_only))
# Usage
cached_client = CachedEdgework()
stats1 = cached_client.get_team_stats_cached("2023-2024") # API call
stats2 = cached_client.get_team_stats_cached("2023-2024") # Cached result
Data Processing Patterns¶
Filtering and Sorting¶
from edgework import Edgework
client = Edgework()
def get_top_players_by_position(season, position, stat='points', limit=10):
"""Get top players for a specific position."""
all_players = client.skater_stats(season=season, limit=200)
# Filter by position
position_players = [p for p in all_players if p.position == position]
# Sort by specified stat
sorted_players = sorted(
position_players,
key=lambda p: getattr(p, stat, 0),
reverse=True
)
return sorted_players[:limit]
# Usage
top_centers = get_top_players_by_position("2023-2024", "C", "points", 5)
for player in top_centers:
print(f"{player.name}: {player.points} points")
Data Transformation¶
def transform_team_data(teams):
"""Transform team data into a more usable format."""
return [
{
'name': team.name,
'abbrev': team.abbrev,
'points': team.points,
'wins': team.wins,
'losses': team.losses,
'goals_per_game': team.goals_for / team.games_played if team.games_played > 0 else 0,
'goals_against_per_game': team.goals_against / team.games_played if team.games_played > 0 else 0,
}
for team in teams
]
# Usage
teams = client.team_stats(season="2023-2024")
transformed = transform_team_data(teams)
Error Handling Patterns¶
Robust API Calls¶
import time
from edgework import Edgework
def safe_api_call(func, max_retries=3, delay=1):
"""Make API call with retry logic."""
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if attempt == max_retries - 1:
raise e
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay}s...")
time.sleep(delay)
delay *= 2 # Exponential backoff
# Usage
client = Edgework()
players = safe_api_call(lambda: client.players(active_only=True))
Validation Patterns¶
def validate_season(season):
"""Validate season format before API calls."""
if not isinstance(season, str):
raise ValueError("Season must be a string")
if not season.count('-') == 1:
raise ValueError("Season must be in format 'YYYY-YYYY'")
years = season.split('-')
if len(years) != 2:
raise ValueError("Invalid season format")
try:
year1, year2 = int(years[0]), int(years[1])
if year2 != year1 + 1:
raise ValueError("Season years must be consecutive")
except ValueError:
raise ValueError("Season years must be integers")
return season
# Usage
def get_stats_safe(client, season):
validated_season = validate_season(season)
return client.skater_stats(season=validated_season)
Working with Rosters¶
Team Roster Analysis¶
def analyze_team_roster(team):
"""Analyze a team's roster composition."""
roster = team.get_roster()
analysis = {
'total_players': len(roster.players),
'forwards': len([p for p in roster.players if p.position in ['C', 'LW', 'RW']]),
'defensemen': len([p for p in roster.players if p.position == 'D']),
'goalies': len([p for p in roster.players if p.position == 'G']),
'positions': {}
}
# Count by specific position
for player in roster.players:
pos = player.position
analysis['positions'][pos] = analysis['positions'].get(pos, 0) + 1
return analysis
# Usage
teams = client.team_stats(season="2023-2024", limit=5)
for team in teams:
analysis = analyze_team_roster(team)
print(f"{team.name}: {analysis['forwards']}F, {analysis['defensemen']}D, {analysis['goalies']}G")
Statistical Analysis Patterns¶
Comparison Functions¶
def compare_players(player1, player2, stats=['goals', 'assists', 'points']):
"""Compare two players across multiple statistics."""
comparison = {}
for stat in stats:
val1 = getattr(player1, stat, 0)
val2 = getattr(player2, stat, 0)
comparison[stat] = {
'player1': val1,
'player2': val2,
'difference': val1 - val2,
'better': player1.name if val1 > val2 else player2.name
}
return comparison
# Usage
players = client.skater_stats(season="2023-2024", limit=10)
if len(players) >= 2:
comparison = compare_players(players[0], players[1])
for stat, data in comparison.items():
print(f"{stat}: {data['better']} is better ({data['difference']:+d})")
League Leaders¶
def get_league_leaders(client, season, categories):
"""Get league leaders in multiple categories."""
leaders = {}
for category in categories:
try:
stats = client.skater_stats(
season=season,
sort=category,
limit=5
)
leaders[category] = stats
except Exception as e:
print(f"Error getting {category} leaders: {e}")
leaders[category] = []
return leaders
# Usage
categories = ['goals', 'assists', 'points', 'plus_minus']
leaders = get_league_leaders(client, "2023-2024", categories)
for category, players in leaders.items():
print(f"\n{category.title()} Leaders:")
for i, player in enumerate(players, 1):
stat_value = getattr(player, category, 'N/A')
print(f"{i}. {player.name}: {stat_value}")
Data Export Patterns¶
JSON Export¶
import json
from datetime import datetime
def export_to_json(data, filename, include_metadata=True):
"""Export data to JSON with metadata."""
export_data = {
'data': data,
}
if include_metadata:
export_data['metadata'] = {
'exported_at': datetime.now().isoformat(),
'record_count': len(data) if isinstance(data, list) else 1,
'source': 'Edgework NHL API Client'
}
with open(filename, 'w', encoding='utf-8') as f:
json.dump(export_data, f, indent=2, default=str)
# Usage
teams = client.team_stats(season="2023-2024")
team_data = [
{
'name': team.name,
'points': team.points,
'wins': team.wins,
'losses': team.losses
}
for team in teams
]
export_to_json(team_data, 'team_standings.json')
Performance Patterns¶
Batch Processing¶
def process_teams_batch(client, season, batch_size=5):
"""Process teams in batches to manage memory."""
teams = client.team_stats(season=season)
for i in range(0, len(teams), batch_size):
batch = teams[i:i + batch_size]
# Process each team in the batch
for team in batch:
try:
roster = team.get_roster()
print(f"Processed {team.name}: {len(roster.players)} players")
except Exception as e:
print(f"Error processing {team.name}: {e}")
# Optional: Add delay between batches
time.sleep(0.5)
# Usage
process_teams_batch(client, "2023-2024")