Hatmanstack commited on
Commit
efaa2dc
·
1 Parent(s): e1d694a

fix: restore player search functionality and add HF frontmatter

Browse files

- Update search_player_by_name to use partial matching via .str.contains()\n- Fix st.multiselect selection loss by preserving current team and selections in options\n- Add Hugging Face frontmatter to README.md for deployment

README.md CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  # NBA Fantasy Predictor
2
 
3
  ![Python](https://img.shields.io/badge/python-3.11+-blue.svg)
 
1
+ ---
2
+ title: NBA Fantasy Predictor
3
+ emoji: 🏀
4
+ colorFrom: blue
5
+ colorTo: white
6
+ sdk: streamlit
7
+ sdk_version: 1.28.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ ---
12
+
13
  # NBA Fantasy Predictor
14
 
15
  ![Python](https://img.shields.io/badge/python-3.11+-blue.svg)
pages/1_home_team.py CHANGED
@@ -103,16 +103,24 @@ def find_home_team() -> pd.DataFrame:
103
  player_search = find_player(player_add)
104
  home_team_df = find_home_team()
105
 
106
- # Combine search results with current team
107
- if not home_team_df.empty:
108
- name_list = home_team_df["FULL_NAME"].tolist()
109
- player_search = player_search + [n for n in name_list if n not in player_search]
 
 
 
 
 
 
 
 
110
 
111
 
112
  def save_state() -> None:
113
  """Save the selected players to session state."""
114
  st.session_state.home_team = st.session_state.player_selector
115
- # No need for st.rerun() inside a callback usually,
116
  # but it doesn't hurt. Streamlit reruns after callback.
117
 
118
 
 
103
  player_search = find_player(player_add)
104
  home_team_df = find_home_team()
105
 
106
+ # Combine search results with current team and current unsaved selections
107
+ # This ensures that selections don't disappear when the search term changes
108
+ current_team_names = home_team_df["FULL_NAME"].tolist() if not home_team_df.empty else []
109
+ current_selections = st.session_state.get("player_selector", [])
110
+
111
+ # Merge all into options list, maintaining uniqueness
112
+ combined_options = list(player_search)
113
+ for name in current_team_names + current_selections:
114
+ if name not in combined_options:
115
+ combined_options.append(name)
116
+
117
+ player_search = combined_options
118
 
119
 
120
  def save_state() -> None:
121
  """Save the selected players to session state."""
122
  st.session_state.home_team = st.session_state.player_selector
123
+ # No need for st.rerun() inside a callback usually,
124
  # but it doesn't hurt. Streamlit reruns after callback.
125
 
126
 
pages/2_play_game.py CHANGED
@@ -127,7 +127,7 @@ else:
127
  # Only generate away team if we don't have one or it's empty
128
  if st.session_state.get("away_team_df") is None or st.session_state.away_team_df.empty:
129
  st.session_state.away_team_df = find_away_team(stats)
130
-
131
  away_data = st.session_state.away_team_df
132
  if away_data.empty:
133
  teams_good = False
 
127
  # Only generate away team if we don't have one or it's empty
128
  if st.session_state.get("away_team_df") is None or st.session_state.away_team_df.empty:
129
  st.session_state.away_team_df = find_away_team(stats)
130
+
131
  away_data = st.session_state.away_team_df
132
  if away_data.empty:
133
  teams_good = False
src/database/queries.py CHANGED
@@ -23,12 +23,12 @@ def search_player_by_name(df: pd.DataFrame, name: str) -> list[tuple[str]]:
23
  """
24
  name_lower = name.lower().strip()
25
  mask = (
26
- (df["FULL_NAME_LOWER"] == name_lower)
27
- | (df["FIRST_NAME_LOWER"] == name_lower)
28
- | (df["LAST_NAME_LOWER"] == name_lower)
29
  )
30
  results = df[mask]["FULL_NAME"].unique().tolist()
31
- return [(name,) for name in results]
32
 
33
 
34
  def get_player_by_full_name(
 
23
  """
24
  name_lower = name.lower().strip()
25
  mask = (
26
+ df["FULL_NAME_LOWER"].str.contains(name_lower, case=False, na=False)
27
+ | df["FIRST_NAME_LOWER"].str.contains(name_lower, case=False, na=False)
28
+ | df["LAST_NAME_LOWER"].str.contains(name_lower, case=False, na=False)
29
  )
30
  results = df[mask]["FULL_NAME"].unique().tolist()
31
+ return [(player_name,) for player_name in results]
32
 
33
 
34
  def get_player_by_full_name(
tests/test_database.py CHANGED
@@ -35,6 +35,11 @@ class TestSearchPlayerByName:
35
  result = search_player_by_name(sample_player_df, "lebron")
36
  assert result == [("LeBron James",)]
37
 
 
 
 
 
 
38
  def test_returns_empty_on_no_match(self, sample_player_df: pd.DataFrame) -> None:
39
  """Verify empty list returned when no player found."""
40
  result = search_player_by_name(sample_player_df, "NonExistent Player")
 
35
  result = search_player_by_name(sample_player_df, "lebron")
36
  assert result == [("LeBron James",)]
37
 
38
+ def test_search_partial_name(self, sample_player_df: pd.DataFrame) -> None:
39
+ """Verify search finds player by partial name."""
40
+ result = search_player_by_name(sample_player_df, "Jord")
41
+ assert result == [("Michael Jordan",)]
42
+
43
  def test_returns_empty_on_no_match(self, sample_player_df: pd.DataFrame) -> None:
44
  """Verify empty list returned when no player found."""
45
  result = search_player_by_name(sample_player_df, "NonExistent Player")