sunmarinup commited on
Commit
585a9bb
·
1 Parent(s): 3182612

Simplify flow

Browse files
Files changed (2) hide show
  1. app.py +6 -15
  2. tests/test_leaderboard.py +55 -72
app.py CHANGED
@@ -6,11 +6,6 @@ import pandas as pd
6
 
7
  from src.about import TITLE, INTRODUCTION_TEXT
8
  from src.display.css_html_js import custom_css
9
- from src.leaderboard.read_evals import (
10
- TabularLeaderboardEntry,
11
- parse_tabular_leaderboard,
12
- tabular_leaderboard_to_dataframe,
13
- )
14
  from src.utils import download_github_file_content
15
 
16
  # GitHub API endpoint for the file (handles Git LFS files)
@@ -29,16 +24,16 @@ DISPLAY_COLUMNS = [
29
  ]
30
 
31
 
32
- def download_leaderboard() -> list[TabularLeaderboardEntry]:
33
  """Download the remote leaderboard CSV from GitHub (handles Git LFS).
34
 
35
- Returns a list of TabularLeaderboardEntry objects.
36
  """
37
  csv_content = download_github_file_content(LEADERBOARD_API_URL, timeout=30)
38
 
39
  df = pd.read_csv(io.StringIO(csv_content))
40
  if df.empty:
41
- return []
42
 
43
  missing_cols = [col for col in DISPLAY_COLUMNS if col not in df.columns]
44
  if missing_cols:
@@ -51,19 +46,15 @@ def download_leaderboard() -> list[TabularLeaderboardEntry]:
51
  df["sem_medal_pct"] = (df["sem_medal_pct"] * 100).round(1)
52
  df["Date"] = pd.to_datetime(df["Date"], errors="coerce").dt.strftime("%Y-%m-%d")
53
 
54
- # Sort by mean_normalized_score before converting to data models
55
  df = df.sort_values(by="mean_normalized_score", ascending=False, ignore_index=True)
56
 
57
- # Parse into data models
58
- entries = parse_tabular_leaderboard(df)
59
-
60
- return entries
61
 
62
 
63
  def refresh_leaderboard():
64
  """Fetch the leaderboard and build the status message for the UI."""
65
- entries = download_leaderboard()
66
- df = tabular_leaderboard_to_dataframe(entries)
67
  status = (
68
  f"Showing data from [GitHub]({LEADERBOARD_GITHUB_URL}). "
69
  f"Last refreshed: {datetime.now(timezone.utc):%Y-%m-%d %H:%M UTC}."
 
6
 
7
  from src.about import TITLE, INTRODUCTION_TEXT
8
  from src.display.css_html_js import custom_css
 
 
 
 
 
9
  from src.utils import download_github_file_content
10
 
11
  # GitHub API endpoint for the file (handles Git LFS files)
 
24
  ]
25
 
26
 
27
+ def download_leaderboard() -> pd.DataFrame:
28
  """Download the remote leaderboard CSV from GitHub (handles Git LFS).
29
 
30
+ Returns a processed DataFrame ready for display.
31
  """
32
  csv_content = download_github_file_content(LEADERBOARD_API_URL, timeout=30)
33
 
34
  df = pd.read_csv(io.StringIO(csv_content))
35
  if df.empty:
36
+ return pd.DataFrame(columns=DISPLAY_COLUMNS)
37
 
38
  missing_cols = [col for col in DISPLAY_COLUMNS if col not in df.columns]
39
  if missing_cols:
 
46
  df["sem_medal_pct"] = (df["sem_medal_pct"] * 100).round(1)
47
  df["Date"] = pd.to_datetime(df["Date"], errors="coerce").dt.strftime("%Y-%m-%d")
48
 
49
+ # Sort by mean_normalized_score
50
  df = df.sort_values(by="mean_normalized_score", ascending=False, ignore_index=True)
51
 
52
+ return df
 
 
 
53
 
54
 
55
  def refresh_leaderboard():
56
  """Fetch the leaderboard and build the status message for the UI."""
57
+ df = download_leaderboard()
 
58
  status = (
59
  f"Showing data from [GitHub]({LEADERBOARD_GITHUB_URL}). "
60
  f"Last refreshed: {datetime.now(timezone.utc):%Y-%m-%d %H:%M UTC}."
tests/test_leaderboard.py CHANGED
@@ -5,7 +5,6 @@ import pytest
5
  import requests
6
 
7
  from app import DISPLAY_COLUMNS, download_leaderboard, refresh_leaderboard
8
- from src.leaderboard.read_evals import TabularLeaderboardEntry
9
 
10
 
11
  @pytest.fixture
@@ -49,12 +48,12 @@ class TestDownloadLeaderboard:
49
  mock_download.return_value = sample_csv_data
50
 
51
  # Execute
52
- entries = download_leaderboard()
53
 
54
  # Assertions
55
- assert isinstance(entries, list)
56
- assert len(entries) == 3
57
- assert all(isinstance(entry, TabularLeaderboardEntry) for entry in entries)
58
  mock_download.assert_called_once()
59
 
60
  @patch("app.download_github_file_content")
@@ -62,68 +61,67 @@ class TestDownloadLeaderboard:
62
  """Test that numeric columns are properly rounded."""
63
  mock_download.return_value = sample_csv_data
64
 
65
- entries = download_leaderboard()
66
 
67
- # Check rounding - entries are sorted by score descending
68
- assert entries[0].mean_normalized_score == 0.912
69
- assert entries[1].mean_normalized_score == 0.854
70
- assert entries[2].mean_normalized_score == 0.789
71
  # Check that scores are floats
72
- assert isinstance(entries[0].mean_normalized_score, float)
73
- assert isinstance(entries[0].std_normalized_score, float)
74
 
75
  @patch("app.download_github_file_content")
76
  def test_percentage_conversion(self, mock_download, sample_csv_data):
77
  """Test that medal percentages are converted from decimal to percentage."""
78
  mock_download.return_value = sample_csv_data
79
 
80
- entries = download_leaderboard()
81
 
82
  # Check percentage conversion (0.876543 * 100 = 87.6543, rounded to 87.7)
83
- # Entries are sorted by score descending: exp_003 (92.3), exp_001 (87.7), exp_002 (76.5)
84
- assert entries[0].mean_medal_pct == 92.3 # exp_003
85
- assert entries[1].mean_medal_pct == 87.7 # exp_001
86
- assert entries[2].mean_medal_pct == 76.5 # exp_002
87
 
88
  @patch("app.download_github_file_content")
89
  def test_date_formatting(self, mock_download, sample_csv_data):
90
  """Test that dates are properly formatted."""
91
  mock_download.return_value = sample_csv_data
92
 
93
- entries = download_leaderboard()
94
 
95
- # Check date formatting - entries sorted by score descending
96
  # exp_003 (2024-02-01), exp_001 (2024-01-15), exp_002 (2024-01-20)
97
- assert entries[0].date == "2024-02-01"
98
- assert entries[1].date == "2024-01-15"
99
- assert entries[2].date == "2024-01-20"
100
 
101
  @patch("app.download_github_file_content")
102
  def test_sorting(self, mock_download, sample_csv_data):
103
- """Test that entries are sorted by mean_normalized_score descending."""
104
  mock_download.return_value = sample_csv_data
105
 
106
- entries = download_leaderboard()
107
 
108
  # Check sorting (highest score first)
109
- scores = [entry.mean_normalized_score for entry in entries]
110
  assert scores == sorted(scores, reverse=True)
111
- assert entries[0].experiment_id == "exp_003" # Highest score
112
- assert entries[2].experiment_id == "exp_002" # Lowest score
113
 
114
  @patch("app.download_github_file_content")
115
  def test_extra_columns_filtered(self, mock_download, sample_csv_with_extra_columns):
116
  """Test that extra columns are filtered out."""
117
  mock_download.return_value = sample_csv_with_extra_columns
118
 
119
- entries = download_leaderboard()
120
 
121
- # Check that entries are created correctly (extra columns should be filtered before parsing)
122
- assert len(entries) == 2
123
- assert all(isinstance(entry, TabularLeaderboardEntry) for entry in entries)
124
- # Verify the data model doesn't have extra columns by converting to dict
125
- entry_dict = entries[0].to_dict()
126
- assert "extra_col" not in entry_dict
127
 
128
  @patch("app.download_github_file_content")
129
  def test_missing_columns_error(self, mock_download, sample_csv_missing_columns):
@@ -172,10 +170,11 @@ class TestDownloadLeaderboard:
172
  csv_data = ",".join(DISPLAY_COLUMNS) # Header only
173
  mock_download.return_value = csv_data
174
 
175
- entries = download_leaderboard()
176
 
177
- assert isinstance(entries, list)
178
- assert len(entries) == 0
 
179
 
180
  @patch("app.download_github_file_content")
181
  def test_invalid_date_handling(self, mock_download):
@@ -188,13 +187,14 @@ class TestDownloadLeaderboard:
188
  )
189
  mock_download.return_value = csv_with_invalid_date
190
 
191
- entries = download_leaderboard()
192
 
193
- # Invalid dates should become NaT and then empty string
194
- # Find entries by experiment_id since order may vary
195
- entry_dict = {entry.experiment_id: entry for entry in entries}
196
- assert entry_dict["exp_001"].date == "nan"
197
- assert entry_dict["exp_002"].date == "2024-01-20"
 
198
 
199
  @patch("app.download_github_file_content")
200
  def test_git_lfs_pointer_file(self, mock_download, sample_csv_data):
@@ -202,12 +202,12 @@ class TestDownloadLeaderboard:
202
  # The utility function handles LFS internally, so we just return the content
203
  mock_download.return_value = sample_csv_data
204
 
205
- entries = download_leaderboard()
206
 
207
  # Should successfully download via download_url
208
- assert isinstance(entries, list)
209
- assert len(entries) == 3
210
- assert all(isinstance(entry, TabularLeaderboardEntry) for entry in entries)
211
  mock_download.assert_called_once()
212
 
213
  @patch("app.download_github_file_content")
@@ -216,33 +216,21 @@ class TestDownloadLeaderboard:
216
  # The utility function handles download_url internally, so we just return the content
217
  mock_download.return_value = sample_csv_data
218
 
219
- entries = download_leaderboard()
220
 
221
- assert isinstance(entries, list)
222
- assert len(entries) == 3
223
- assert all(isinstance(entry, TabularLeaderboardEntry) for entry in entries)
224
  mock_download.assert_called_once()
225
 
226
 
227
  class TestRefreshLeaderboard:
228
  """Tests for refresh_leaderboard function."""
229
 
230
- @patch("app.tabular_leaderboard_to_dataframe")
231
  @patch("app.download_leaderboard")
232
- def test_refresh_leaderboard_success(self, mock_download, mock_to_df):
233
  """Test that refresh_leaderboard returns dataframe and status message."""
234
  # Setup mocks
235
- mock_entry = TabularLeaderboardEntry(
236
- experiment_id="exp_001",
237
- agent="Agent A",
238
- llms_used="GPT-4",
239
- mean_normalized_score=0.85,
240
- std_normalized_score=0.01,
241
- mean_medal_pct=87.0,
242
- sem_medal_pct=1.0,
243
- date="2024-01-15",
244
- )
245
- mock_entries = [mock_entry]
246
  mock_df = pd.DataFrame(
247
  {
248
  "experiment_id": ["exp_001"],
@@ -250,8 +238,7 @@ class TestRefreshLeaderboard:
250
  "Agent": ["Agent A"],
251
  }
252
  )
253
- mock_download.return_value = mock_entries
254
- mock_to_df.return_value = mock_df
255
 
256
  # Execute
257
  df, status = refresh_leaderboard()
@@ -269,16 +256,12 @@ class TestRefreshLeaderboard:
269
  timestamp_pattern = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2} UTC"
270
  assert re.search(timestamp_pattern, status) is not None
271
  mock_download.assert_called_once()
272
- mock_to_df.assert_called_once_with(mock_entries)
273
 
274
- @patch("app.tabular_leaderboard_to_dataframe")
275
  @patch("app.download_leaderboard")
276
- def test_refresh_leaderboard_includes_url(self, mock_download, mock_to_df):
277
  """Test that status message includes the GitHub URL."""
278
- mock_entries = []
279
  mock_df = pd.DataFrame()
280
- mock_download.return_value = mock_entries
281
- mock_to_df.return_value = mock_df
282
 
283
  df, status = refresh_leaderboard()
284
 
 
5
  import requests
6
 
7
  from app import DISPLAY_COLUMNS, download_leaderboard, refresh_leaderboard
 
8
 
9
 
10
  @pytest.fixture
 
48
  mock_download.return_value = sample_csv_data
49
 
50
  # Execute
51
+ df = download_leaderboard()
52
 
53
  # Assertions
54
+ assert isinstance(df, pd.DataFrame)
55
+ assert len(df) == 3
56
+ assert list(df.columns) == DISPLAY_COLUMNS
57
  mock_download.assert_called_once()
58
 
59
  @patch("app.download_github_file_content")
 
61
  """Test that numeric columns are properly rounded."""
62
  mock_download.return_value = sample_csv_data
63
 
64
+ df = download_leaderboard()
65
 
66
+ # Check rounding - df is sorted by score descending
67
+ assert df.iloc[0]["mean_normalized_score"] == 0.912
68
+ assert df.iloc[1]["mean_normalized_score"] == 0.854
69
+ assert df.iloc[2]["mean_normalized_score"] == 0.789
70
  # Check that scores are floats
71
+ assert isinstance(df.iloc[0]["mean_normalized_score"], float)
72
+ assert isinstance(df.iloc[0]["std_normalized_score"], float)
73
 
74
  @patch("app.download_github_file_content")
75
  def test_percentage_conversion(self, mock_download, sample_csv_data):
76
  """Test that medal percentages are converted from decimal to percentage."""
77
  mock_download.return_value = sample_csv_data
78
 
79
+ df = download_leaderboard()
80
 
81
  # Check percentage conversion (0.876543 * 100 = 87.6543, rounded to 87.7)
82
+ # df is sorted by score descending: exp_003 (92.3), exp_001 (87.7), exp_002 (76.5)
83
+ assert df.iloc[0]["mean_medal_pct"] == 92.3 # exp_003
84
+ assert df.iloc[1]["mean_medal_pct"] == 87.7 # exp_001
85
+ assert df.iloc[2]["mean_medal_pct"] == 76.5 # exp_002
86
 
87
  @patch("app.download_github_file_content")
88
  def test_date_formatting(self, mock_download, sample_csv_data):
89
  """Test that dates are properly formatted."""
90
  mock_download.return_value = sample_csv_data
91
 
92
+ df = download_leaderboard()
93
 
94
+ # Check date formatting - df sorted by score descending
95
  # exp_003 (2024-02-01), exp_001 (2024-01-15), exp_002 (2024-01-20)
96
+ assert df.iloc[0]["Date"] == "2024-02-01"
97
+ assert df.iloc[1]["Date"] == "2024-01-15"
98
+ assert df.iloc[2]["Date"] == "2024-01-20"
99
 
100
  @patch("app.download_github_file_content")
101
  def test_sorting(self, mock_download, sample_csv_data):
102
+ """Test that df is sorted by mean_normalized_score descending."""
103
  mock_download.return_value = sample_csv_data
104
 
105
+ df = download_leaderboard()
106
 
107
  # Check sorting (highest score first)
108
+ scores = df["mean_normalized_score"].tolist()
109
  assert scores == sorted(scores, reverse=True)
110
+ assert df.iloc[0]["experiment_id"] == "exp_003" # Highest score
111
+ assert df.iloc[2]["experiment_id"] == "exp_002" # Lowest score
112
 
113
  @patch("app.download_github_file_content")
114
  def test_extra_columns_filtered(self, mock_download, sample_csv_with_extra_columns):
115
  """Test that extra columns are filtered out."""
116
  mock_download.return_value = sample_csv_with_extra_columns
117
 
118
+ df = download_leaderboard()
119
 
120
+ # Check that df is created correctly (extra columns should be filtered)
121
+ assert len(df) == 2
122
+ assert list(df.columns) == DISPLAY_COLUMNS
123
+ # Verify the df doesn't have extra columns
124
+ assert "extra_col" not in df.columns
 
125
 
126
  @patch("app.download_github_file_content")
127
  def test_missing_columns_error(self, mock_download, sample_csv_missing_columns):
 
170
  csv_data = ",".join(DISPLAY_COLUMNS) # Header only
171
  mock_download.return_value = csv_data
172
 
173
+ df = download_leaderboard()
174
 
175
+ assert isinstance(df, pd.DataFrame)
176
+ assert len(df) == 0
177
+ assert list(df.columns) == DISPLAY_COLUMNS
178
 
179
  @patch("app.download_github_file_content")
180
  def test_invalid_date_handling(self, mock_download):
 
187
  )
188
  mock_download.return_value = csv_with_invalid_date
189
 
190
+ df = download_leaderboard()
191
 
192
+ # Invalid dates should become NaT and then "nan" string
193
+ # Find rows by experiment_id since order may vary
194
+ row_001 = df[df["experiment_id"] == "exp_001"].iloc[0]
195
+ row_002 = df[df["experiment_id"] == "exp_002"].iloc[0]
196
+ assert pd.isna(row_001["Date"])
197
+ assert row_002["Date"] == "2024-01-20"
198
 
199
  @patch("app.download_github_file_content")
200
  def test_git_lfs_pointer_file(self, mock_download, sample_csv_data):
 
202
  # The utility function handles LFS internally, so we just return the content
203
  mock_download.return_value = sample_csv_data
204
 
205
+ df = download_leaderboard()
206
 
207
  # Should successfully download via download_url
208
+ assert isinstance(df, pd.DataFrame)
209
+ assert len(df) == 3
210
+ assert list(df.columns) == DISPLAY_COLUMNS
211
  mock_download.assert_called_once()
212
 
213
  @patch("app.download_github_file_content")
 
216
  # The utility function handles download_url internally, so we just return the content
217
  mock_download.return_value = sample_csv_data
218
 
219
+ df = download_leaderboard()
220
 
221
+ assert isinstance(df, pd.DataFrame)
222
+ assert len(df) == 3
223
+ assert list(df.columns) == DISPLAY_COLUMNS
224
  mock_download.assert_called_once()
225
 
226
 
227
  class TestRefreshLeaderboard:
228
  """Tests for refresh_leaderboard function."""
229
 
 
230
  @patch("app.download_leaderboard")
231
+ def test_refresh_leaderboard_success(self, mock_download):
232
  """Test that refresh_leaderboard returns dataframe and status message."""
233
  # Setup mocks
 
 
 
 
 
 
 
 
 
 
 
234
  mock_df = pd.DataFrame(
235
  {
236
  "experiment_id": ["exp_001"],
 
238
  "Agent": ["Agent A"],
239
  }
240
  )
241
+ mock_download.return_value = mock_df
 
242
 
243
  # Execute
244
  df, status = refresh_leaderboard()
 
256
  timestamp_pattern = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2} UTC"
257
  assert re.search(timestamp_pattern, status) is not None
258
  mock_download.assert_called_once()
 
259
 
 
260
  @patch("app.download_leaderboard")
261
+ def test_refresh_leaderboard_includes_url(self, mock_download):
262
  """Test that status message includes the GitHub URL."""
 
263
  mock_df = pd.DataFrame()
264
+ mock_download.return_value = mock_df
 
265
 
266
  df, status = refresh_leaderboard()
267