Fix auto-draft player availability check with nested API parsing
DraftList.from_api_data() now properly calls Player.from_api_data() for nested player objects, ensuring player.team_id is correctly extracted from the nested team object. Also fixed validate_cap_space() unpacking to accept all 3 return values. Bug: Auto-draft was marking all players as "not available" because player.team_id was None (None != 547 always True). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
9093055bb5
commit
602c87590e
@ -3,7 +3,7 @@ Draft preference list model
|
||||
|
||||
Represents team draft board rankings and preferences.
|
||||
"""
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, Any
|
||||
from pydantic import Field
|
||||
|
||||
from models.base import SBABaseModel
|
||||
@ -21,6 +21,32 @@ class DraftList(SBABaseModel):
|
||||
team: Team = Field(..., description="Team object")
|
||||
player: Player = Field(..., description="Player object")
|
||||
|
||||
@classmethod
|
||||
def from_api_data(cls, data: Dict[str, Any]) -> 'DraftList':
|
||||
"""
|
||||
Create DraftList instance from API data, ensuring nested objects are properly handled.
|
||||
|
||||
The API returns nested team and player objects. We need to ensure Player.from_api_data()
|
||||
is called so that player.team_id is properly extracted from the nested team object.
|
||||
Without this, Pydantic's default construction doesn't call from_api_data() on nested
|
||||
objects, leaving player.team_id as None.
|
||||
"""
|
||||
if not data:
|
||||
raise ValueError("Cannot create DraftList from empty data")
|
||||
|
||||
# Make a copy to avoid modifying original
|
||||
draft_list_data = data.copy()
|
||||
|
||||
# Handle nested team object
|
||||
if 'team' in draft_list_data and isinstance(draft_list_data['team'], dict):
|
||||
draft_list_data['team'] = Team.from_api_data(draft_list_data['team'])
|
||||
|
||||
# Handle nested player object - CRITICAL for team_id extraction
|
||||
if 'player' in draft_list_data and isinstance(draft_list_data['player'], dict):
|
||||
draft_list_data['player'] = Player.from_api_data(draft_list_data['player'])
|
||||
|
||||
return cls(**draft_list_data)
|
||||
|
||||
@property
|
||||
def team_id(self) -> int:
|
||||
"""Extract team ID from nested team object."""
|
||||
|
||||
@ -225,13 +225,24 @@ class DraftMonitorTask:
|
||||
# Try each player in order
|
||||
for entry in draft_list:
|
||||
if not entry.player:
|
||||
self.logger.debug(f"Draft list entry has no player, skipping")
|
||||
continue
|
||||
|
||||
player = entry.player
|
||||
|
||||
# Debug: Log player team_id for troubleshooting
|
||||
self.logger.debug(
|
||||
f"Checking player {player.name}: team_id={player.team_id}, "
|
||||
f"FA team_id={config.free_agent_team_id}, "
|
||||
f"team.id={player.team.id if player.team else 'None'}"
|
||||
)
|
||||
|
||||
# Check if player is still available
|
||||
if player.team_id != config.free_agent_team_id:
|
||||
self.logger.debug(f"Player {player.name} no longer available, skipping")
|
||||
self.logger.debug(
|
||||
f"Player {player.name} no longer available "
|
||||
f"(team_id={player.team_id} != FA={config.free_agent_team_id}), skipping"
|
||||
)
|
||||
continue
|
||||
|
||||
# Attempt to draft this player
|
||||
@ -299,7 +310,7 @@ class DraftMonitorTask:
|
||||
return False
|
||||
|
||||
# Validate cap space
|
||||
is_valid, projected_total = await validate_cap_space(roster, player.wara)
|
||||
is_valid, projected_total, cap_limit = await validate_cap_space(roster, player.wara)
|
||||
|
||||
if not is_valid:
|
||||
self.logger.debug(
|
||||
|
||||
@ -474,6 +474,68 @@ class TestDraftListModel:
|
||||
assert top_pick.is_top_ranked is True
|
||||
assert lower_pick.is_top_ranked is False
|
||||
|
||||
def test_draft_list_from_api_data_extracts_player_team_id(self):
|
||||
"""
|
||||
Test that DraftList.from_api_data() properly extracts player.team_id from nested team object.
|
||||
|
||||
This is critical for auto-draft functionality. The API returns player data with a nested
|
||||
team object (not a flat team_id). Without the custom from_api_data(), Pydantic's default
|
||||
construction doesn't call Player.from_api_data(), leaving player.team_id as None.
|
||||
|
||||
Bug fixed: Auto-draft was failing because player.team_id was None, causing all players
|
||||
to be incorrectly marked as "not available" (None != 547 always True).
|
||||
"""
|
||||
# Simulate API response format - nested objects, NOT flat IDs
|
||||
api_response = {
|
||||
'id': 303,
|
||||
'season': 13,
|
||||
'rank': 1,
|
||||
'team': {
|
||||
'id': 548,
|
||||
'abbrev': 'WV',
|
||||
'sname': 'Black Bears',
|
||||
'lname': 'West Virginia Black Bears',
|
||||
'season': 13
|
||||
},
|
||||
'player': {
|
||||
'id': 12843,
|
||||
'name': 'George Springer',
|
||||
'wara': 0.31,
|
||||
'image': 'https://example.com/springer.png',
|
||||
'season': 13,
|
||||
'pos_1': 'CF',
|
||||
# Note: NO flat team_id here - it's nested in 'team' below
|
||||
'team': {
|
||||
'id': 547, # Free Agent team
|
||||
'abbrev': 'FA',
|
||||
'sname': 'Free Agents',
|
||||
'lname': 'Free Agents',
|
||||
'season': 13
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create DraftList using from_api_data (what BaseService calls)
|
||||
draft_entry = DraftList.from_api_data(api_response)
|
||||
|
||||
# Verify nested objects are created
|
||||
assert draft_entry.team is not None
|
||||
assert draft_entry.player is not None
|
||||
|
||||
# CRITICAL: player.team_id must be extracted from nested team object
|
||||
assert draft_entry.player.team_id == 547, \
|
||||
f"player.team_id should be 547 (FA), got {draft_entry.player.team_id}"
|
||||
|
||||
# Verify the nested team object is also populated
|
||||
assert draft_entry.player.team is not None
|
||||
assert draft_entry.player.team.id == 547
|
||||
assert draft_entry.player.team.abbrev == 'FA'
|
||||
|
||||
# Verify DraftList's own team data
|
||||
assert draft_entry.team.id == 548
|
||||
assert draft_entry.team.abbrev == 'WV'
|
||||
assert draft_entry.team_id == 548 # Property from nested team
|
||||
|
||||
|
||||
class TestModelCoverageExtras:
|
||||
"""Additional model coverage tests."""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user