hotfix: make ScorecardTracker methods async to match await callers #117

Merged
cal merged 1 commits from hotfix/scorecard-tracker-async into main 2026-03-20 18:41:45 +00:00
3 changed files with 25 additions and 19 deletions

View File

@ -61,7 +61,7 @@ class ScorecardTracker:
except Exception as e:
logger.error(f"Failed to save scorecard data: {e}")
def publish_scorecard(
async def publish_scorecard(
self, text_channel_id: int, sheet_url: str, publisher_id: int
) -> None:
"""
@ -82,7 +82,7 @@ class ScorecardTracker:
self.save_data()
logger.info(f"Published scorecard to channel {text_channel_id}: {sheet_url}")
def unpublish_scorecard(self, text_channel_id: int) -> bool:
async def unpublish_scorecard(self, text_channel_id: int) -> bool:
"""
Remove scorecard from a text channel.
@ -103,7 +103,7 @@ class ScorecardTracker:
return False
def get_scorecard(self, text_channel_id: int) -> Optional[str]:
async def get_scorecard(self, text_channel_id: int) -> Optional[str]:
"""
Get scorecard URL for a text channel.
@ -118,7 +118,7 @@ class ScorecardTracker:
scorecard_data = scorecards.get(str(text_channel_id))
return scorecard_data["sheet_url"] if scorecard_data else None
def get_all_scorecards(self) -> List[Tuple[int, str]]:
async def get_all_scorecards(self) -> List[Tuple[int, str]]:
"""
Get all published scorecards.
@ -132,7 +132,7 @@ class ScorecardTracker:
for channel_id, data in scorecards.items()
]
def update_timestamp(self, text_channel_id: int) -> None:
async def update_timestamp(self, text_channel_id: int) -> None:
"""
Update the last_updated timestamp for a scorecard.
@ -146,7 +146,7 @@ class ScorecardTracker:
scorecards[channel_key]["last_updated"] = datetime.now(UTC).isoformat()
self.save_data()
def cleanup_stale_entries(self, valid_channel_ids: List[int]) -> int:
async def cleanup_stale_entries(self, valid_channel_ids: List[int]) -> int:
"""
Remove tracking entries for text channels that no longer exist.

View File

@ -128,7 +128,7 @@ class VoiceChannelCleanupService:
if channel_data and channel_data.get("text_channel_id"):
try:
text_channel_id_int = int(channel_data["text_channel_id"])
was_unpublished = self.scorecard_tracker.unpublish_scorecard(
was_unpublished = await self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
)
if was_unpublished:
@ -218,8 +218,10 @@ class VoiceChannelCleanupService:
if text_channel_id:
try:
text_channel_id_int = int(text_channel_id)
was_unpublished = self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
was_unpublished = (
await self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
)
)
if was_unpublished:
self.logger.info(
@ -244,8 +246,10 @@ class VoiceChannelCleanupService:
if text_channel_id:
try:
text_channel_id_int = int(text_channel_id)
was_unpublished = self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
was_unpublished = (
await self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
)
)
if was_unpublished:
self.logger.info(
@ -330,7 +334,7 @@ class VoiceChannelCleanupService:
if text_channel_id:
try:
text_channel_id_int = int(text_channel_id)
was_unpublished = self.scorecard_tracker.unpublish_scorecard(
was_unpublished = await self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
)
if was_unpublished:
@ -358,7 +362,7 @@ class VoiceChannelCleanupService:
if text_channel_id:
try:
text_channel_id_int = int(text_channel_id)
was_unpublished = self.scorecard_tracker.unpublish_scorecard(
was_unpublished = await self.scorecard_tracker.unpublish_scorecard(
text_channel_id_int
)
if was_unpublished:

View File

@ -24,7 +24,8 @@ from utils.scorebug_helpers import create_scorebug_embed, create_team_progress_b
class TestScorecardTrackerFreshReads:
"""Tests that ScorecardTracker reads fresh data from disk (fix for #40)."""
def test_get_all_scorecards_reads_fresh_data(self, tmp_path):
@pytest.mark.asyncio
async def test_get_all_scorecards_reads_fresh_data(self, tmp_path):
"""get_all_scorecards() should pick up scorecards written by another process.
Simulates the background task having a stale tracker instance while
@ -34,7 +35,7 @@ class TestScorecardTrackerFreshReads:
data_file.write_text(json.dumps({"scorecards": {}}))
tracker = ScorecardTracker(data_file=str(data_file))
assert tracker.get_all_scorecards() == []
assert await tracker.get_all_scorecards() == []
# Another process writes a scorecard to the same file
new_data = {
@ -51,17 +52,18 @@ class TestScorecardTrackerFreshReads:
data_file.write_text(json.dumps(new_data))
# Should see the new scorecard without restart
result = tracker.get_all_scorecards()
result = await tracker.get_all_scorecards()
assert len(result) == 1
assert result[0] == (111, "https://docs.google.com/spreadsheets/d/abc123")
def test_get_scorecard_reads_fresh_data(self, tmp_path):
@pytest.mark.asyncio
async def test_get_scorecard_reads_fresh_data(self, tmp_path):
"""get_scorecard() should pick up a scorecard written by another process."""
data_file = tmp_path / "scorecards.json"
data_file.write_text(json.dumps({"scorecards": {}}))
tracker = ScorecardTracker(data_file=str(data_file))
assert tracker.get_scorecard(222) is None
assert await tracker.get_scorecard(222) is None
# Another process writes a scorecard
new_data = {
@ -79,7 +81,7 @@ class TestScorecardTrackerFreshReads:
# Should see the new scorecard
assert (
tracker.get_scorecard(222)
await tracker.get_scorecard(222)
== "https://docs.google.com/spreadsheets/d/xyz789"
)