Browse Source

Clean up and let nba_api handle timeouts

bryan 4 years ago
parent
commit
127f9f3d72
2 changed files with 202 additions and 178 deletions
  1. 202 175
      nba_playoffs_game_updater.py
  2. 0 3
      requirements.txt

+ 202 - 175
nba_playoffs_game_updater.py

@@ -4,199 +4,226 @@ import gspread
 from oauth2client.service_account import ServiceAccountCredentials
 import datetime
 import time
-import timeout_decorator
 from nba_api.stats.static import players
 from nba_api.stats.endpoints import playergamelog
 
-#spreadsheet_key = '12Zv95ZMJ008KXC5ytVnBusjX9wUnpOg0TOLwmxMNOTQ' # 2018 Official
-spreadsheet_key = '14pHOScaGXvN83iCca6_5p6QoViYvo223cIJD9nnl7TI' # 2019 Test
+spreadsheet_key = '1QBQvGSMesox1gwjpaoK-0-p3n-c4I_L73PWCggjdayM' # 2019 Official
+#spreadsheet_key = '14pHOScaGXvN83iCca6_5p6QoViYvo223cIJD9nnl7TI' # 2019 Test
 json_keyfile = 'NBA Playoffs Game-1f9a46f0715c.json'
-#current_day = 'today' # today, else:
-current_day = datetime.date(2018, 4, 14) # set date manually
-nba_cooldown = 1 # in seconds, don't hammer the NBA.com API too hard
+current_day = 'today' # today, else:
+#current_day = datetime.date(2018, 4, 15) # set date manually
+nba_cooldown = 2 # in seconds, don't hammer the NBA.com API too hard
 
-####################################################################################
+###############################################################################
 
 def getWorksheet(spreadsheet_key, json_keyfile):
-  scope = ['https://spreadsheets.google.com/feeds',
-           'https://www.googleapis.com/auth/drive']
-  credentials = ServiceAccountCredentials.from_json_keyfile_name(json_keyfile, scope)
-  gc = gspread.authorize(credentials)
-  spreadsheet = gc.open_by_key(spreadsheet_key)
-  worksheet = spreadsheet.get_worksheet(0)
-  return worksheet
+    scope = ['https://spreadsheets.google.com/feeds',
+                     'https://www.googleapis.com/auth/drive']
+    credentials = ServiceAccountCredentials.from_json_keyfile_name(json_keyfile, scope)
+    gc = gspread.authorize(credentials)
+    spreadsheet = gc.open_by_key(spreadsheet_key)
+    worksheet = spreadsheet.get_worksheet(0)
+    return worksheet
 
 def setDates(current_day):
-  if current_day == 'today':
-    current_day = datetime.datetime.now() - datetime.timedelta(hours=3) # in case games go past midnight
-    current_day = current_day.date()
-  url_date = current_day.strftime('%m/%d/%Y')
-  current_year = current_day.year
-  if current_day.month > 6:
-    current_season = str(current_year) + "-" + str(current_year + 1)[2:]
-  else:
-    current_season = str(current_year - 1) + "-" + str(current_year)[2:]
-  return url_date, current_season, current_day
-  
-def getFirstRowLastRow(worksheet, current_day):
-  date_col_values = worksheet.col_values(1) # get all date cell values from column 1
-  final_row = len(date_col_values) # get number of rows in spreadsheet
-  date_cells = worksheet.range('A4:A'+str(final_row)) # get all date cells
-  first_row = ""
-  last_row = ""
-  for date_cell in date_cells:
-    if first_row != "":
-      if date_cell.row == final_row:
-        last_row = final_row
-      elif date_cell.value != "":
-        last_row = date_cell.row - 1
-        break
-      else:
-        continue
-    elif date_cell.value != "":
-      date_cell_day = datetime.datetime.strptime(date_cell.value + " " + str(current_day.year), '%A, %B %d %Y')
-      date_cell_day = date_cell_day.date()
-      if date_cell_day == current_day:
-        first_row = date_cell.row
-  return first_row, last_row
+    if current_day == 'today':
+        # in case games go past midnight
+        current_date = datetime.datetime.now() - datetime.timedelta(hours=3)
+        current_date = current_date.date()
+    else:
+        current_date = current_day
+    url_date = current_date.strftime('%m/%d/%Y')
+    current_year = current_date.year
+    if current_date.month > 6:
+        current_season = '{}-{}'.format(str(current_year), 
+                                        str(current_year + 1)[2:])
+    else:
+        current_season = '{}-{}'.format(str(current_year - 1), 
+                                        str(current_year)[2:])
+    return url_date, current_season, current_date
+    
+def getFirstRowLastRow(worksheet, current_date):
+    date_col_values = worksheet.col_values(1) # get all date cell values from column 1
+    final_row = len(date_col_values) # get number of rows in spreadsheet
+    date_cells = worksheet.range('A4:A'+str(final_row)) # get all date cells
+    first_row = ""
+    last_row = ""
+    for date_cell in date_cells:
+        if first_row != "":
+            if date_cell.row == final_row:
+                last_row = final_row
+                break
+            elif date_cell.value != "":
+                last_row = date_cell.row - 1
+                break
+            continue
+        elif date_cell.value != "":
+            date_cell_day = datetime.datetime.strptime('{} {}'.format(date_cell.value, 
+                                                       str(current_date.year)), 
+                                                       '%A, %B %d %Y')
+            date_cell_day = date_cell_day.date()
+            if date_cell_day == current_date:
+                first_row = date_cell.row
+    return first_row, last_row
 
 def parsePlayersCells(todays_cells):
-  player_cells = []
-  player_names = []
-  for cell in todays_cells:
-    if cell.col == 3 and cell.value != "":
-      player_cells.append(cell)
-      player_name = cleanPlayerName(cell)
-      player_names.append(player_name)
-  player_names_unique = list(dict.fromkeys(player_names))
-  return player_cells, player_names_unique
-    
+    player_cells = []
+    player_names = []
+    for cell in todays_cells:
+        if cell.col == 3 and cell.value != "" and cell.value[-7:] != "-FIX!!!":
+            player_cells.append(cell)
+            player_name = cleanPlayerName(cell)
+            player_names.append(player_name)
+    player_names_unique = list(dict.fromkeys(player_names))
+    return player_cells, player_names_unique
+        
 def cleanPlayerName(player_cell):
-  raw_name = player_cell.value
-  first_name_last_name = raw_name.split()
-  first_name = first_name_last_name[0]
-  first_name = first_name.replace('.', '')
-  last_name = first_name_last_name[1]
-  player_name = first_name + ' ' + last_name
-  return player_name
-  
-def badName(worksheet, player_cell):
-  worksheet.update_cell(player_cell.row, 12, "Fix name, then delete this message!")
-
-@timeout_decorator.timeout(10)
+    raw_name = player_cell.value
+    first_name_last_name = raw_name.split()
+    first_name = first_name_last_name[0]
+    first_name = first_name.replace('.', '')
+    last_name = first_name_last_name[1]
+    player_name = first_name + ' ' + last_name
+    return player_name
+
 def getPlayerStats(player_id, url_date, current_season):
-  player_stats = {}
-  player_game_logs = playergamelog.PlayerGameLog(player_id=player_id,
-                                          season_all=current_season,
-                                          league_id_nullable='00',
-                                          season_type_all_star='Playoffs',
-                                          date_from_nullable=url_date,
-                                          date_to_nullable=url_date)
-  player_game_logs = player_game_logs.get_dict()
-  player_game_logs_results = player_game_logs.get('resultSets')[0]
-  player_game_logs_headers = player_game_logs_results.get('headers')
-  player_game_logs_values = player_game_logs_results.get('rowSet')[0]
-  player_stats_dict = dict(zip(player_game_logs_headers, player_game_logs_values))
-  return player_stats_dict
-
-@timeout_decorator.timeout(60)
+    player_game_logs = playergamelog.PlayerGameLog(player_id=player_id,
+                                                   league_id_nullable='00',
+                                                   season_type_all_star='Playoffs',
+                                                   date_from_nullable=url_date,
+                                                   date_to_nullable=url_date)
+    player_game_logs = player_game_logs.get_dict()
+    player_game_logs_results = player_game_logs.get('resultSets')[0]
+    player_game_logs_headers = player_game_logs_results.get('headers')
+    # if player has no stats for this day, list will be empty
+    if len(player_game_logs_results.get('rowSet')) < 1:
+        player_stats_dict = None
+    else:
+        player_game_logs_values = player_game_logs_results.get('rowSet')[0]
+        player_stats_dict = dict(zip(player_game_logs_headers, player_game_logs_values))
+    return player_stats_dict
+
 def buildStatsDict(player_names_unique, url_date, current_season):
-  stats_dict = {}
-  for player_name in player_names_unique:
-    print("Getting " + player_name + "\'s stats from NBA.com")
-    player_info = players.find_players_by_full_name(player_name)
-    player_id = player_info[0].get('id')
-    player_stats_dict = getPlayerStats(player_id, url_date, current_season)
-    stats_dict[player_name] = player_stats_dict
-    time.sleep(nba_cooldown)
-  return stats_dict
-
-def checkStatsDict(player_name, stats_dict):
-  player_stats_dict = stats_dict.get(player_name)
-  return player_stats_dict
-
-def updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update):
-  for cell in todays_cells:
-    if cell.row == player_cell.row:
-      if cell.col == 4 and player_stats_dict.get("PTS") != "" and str(cell.value) != str(player_stats_dict.get("PTS")):
-        cell.value = int(player_stats_dict.get("PTS"))
-        update = True
-      elif cell.col == 5 and player_stats_dict.get("REB") != "" and str(cell.value) != str(player_stats_dict.get("REB")):
-        cell.value = int(player_stats_dict.get("REB"))
-        update = True
-      elif cell.col == 6 and player_stats_dict.get("AST") != "" and str(cell.value) != str(player_stats_dict.get("AST")):
-         cell.value = int(player_stats_dict.get("AST"))
-         update = True
-      elif cell.col == 7 and player_stats_dict.get("STL") != "" and str(cell.value) != str(player_stats_dict.get("STL")):
-         cell.value = int(player_stats_dict.get("STL"))
-         update = True
-      elif cell.col == 8 and player_stats_dict.get("BLK") != "" and str(cell.value) != str(player_stats_dict.get("BLK")):
-         cell.value = int(player_stats_dict.get("BLK"))
-         update = True
-      elif cell.col == 9 and player_stats_dict.get("TOV") != "" and str(cell.value) != str(player_stats_dict.get("TOV")):
-         cell.value = int(player_stats_dict.get("TOV"))
-         update = True
-      elif cell.col == 10 and player_stats_dict.get("WL") != "" and str(cell.value) != str(player_stats_dict.get("WL")):
-         cell.value = str(player_stats_dict.get("WL"))
-         update = True
-  return todays_cells, update
-      
+    stats_dict = {}
+    for player_name in player_names_unique:
+        player_info = players.find_players_by_full_name(player_name)
+        if len(player_info) < 1:
+            print("\nPlayer \"" + player_name + "\" not found, please fix name!")
+            stats_dict[player_name] = "Fix Name!"
+            continue
+        player_id = player_info[0].get('id')
+        stats_dict[player_name] = getPlayerStats(player_id, url_date, current_season)
+        print('{} {}{} {}{}'.format('Got', player_name, '\'s (ID:', str(player_id), ') stats from NBA.com'))
+        time.sleep(nba_cooldown)
+    return stats_dict
+
+def updatePlayerStatsLocal(todays_cells, player_cell, player_stats, update, player_update):
+    for cell in todays_cells:
+        if cell.row == player_cell.row:
+            if (cell.col == 4 and player_stats.get("PTS") != "" and 
+                str(cell.value) != str(player_stats.get("PTS"))):
+                cell.value = str(player_stats.get("PTS"))
+                update = True
+                player_update = True
+            elif (cell.col == 5 and player_stats.get("REB") != "" and 
+                 str(cell.value) != str(player_stats.get("REB"))):
+                cell.value = str(player_stats.get("REB"))
+                update = True
+                player_update = True
+            elif (cell.col == 6 and player_stats.get("AST") != "" and 
+                 str(cell.value) != str(player_stats.get("AST"))):
+                cell.value = str(player_stats.get("AST"))
+                update = True
+                player_update = True
+            elif (cell.col == 7 and player_stats.get("STL") != "" and 
+                 str(cell.value) != str(player_stats.get("STL"))):
+                cell.value = str(player_stats.get("STL"))
+                update = True
+                player_update = True
+            elif (cell.col == 8 and player_stats.get("BLK") != "" and 
+                 str(cell.value) != str(player_stats.get("BLK"))):
+                cell.value = str(player_stats.get("BLK"))
+                update = True
+                player_update = True
+            elif (cell.col == 9 and player_stats.get("TOV") != "" and 
+                 str(cell.value) != str(player_stats.get("TOV"))):
+                cell.value = str(player_stats.get("TOV"))
+                update = True
+                player_update = True
+            elif (cell.col == 10 and player_stats.get("WL") != "" and 
+                 str(cell.value) != str(player_stats.get("WL"))):
+                cell.value = str(player_stats.get("WL"))
+                update = True
+                player_update = True
+    return todays_cells, update, player_update
+            
 
 
 if __name__ == "__main__":
 
-  while True:
-
-    url_date, current_season, current_day = setDates(current_day)
-    
-    try:
-      worksheet = getWorksheet(spreadsheet_key, json_keyfile)
-      first_row, last_row = getFirstRowLastRow(worksheet, current_day)
-      if first_row == "":
-        print("No games today! Pausing for 1000 seconds...")
-        time.sleep(1000)
-        continue
-      todays_cells = worksheet.range(first_row, 3, last_row, 10)
-      print("Getting a list of today's players...")
-      player_cells, player_names_unique = parsePlayersCells(todays_cells)
-      print(player_names_unique)
-    except gspread.exceptions.APIError:
-      print("API overloaded, retrying in 10 seconds...")
-      time.sleep(10)
-      continue
-    except:
-      time.sleep(10)
-      continue
-
-    try:
-      stats_dict = buildStatsDict(player_names_unique, url_date, current_season)
-    except timeout_decorator.TimeoutError:
-      print("NBA.com API not responding, retrying in 10 seconds...")
-      time.sleep(10)
-      continue
-
-    update = False # only update the sheet if it's changed
-    
-    for player_cell in player_cells:
-      player_name = cleanPlayerName(player_cell)
-      player_stats_dict = checkStatsDict(player_name, stats_dict)
-      print("Updating " + player_name + "\'s stats locally")
-      todays_cells, update = updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update)
-          
-    if update == True:
-      while True:
-        try: 
-          print("Updating google sheet remotely...")
-          worksheet.update_cells(todays_cells)
-          break
-        except gspread.exceptions.APIError:
-          print("API overloaded, adding a 10 second delay...")
-          time.sleep(10)
-          continue
-    else:
-      print("No remote update necessary...")
-      time.sleep(30)
+    while True:
+        url_date, current_season, current_date = setDates(current_day)
+        print("Date: " + str(current_date))
         
-    continue # restart entire loop
+        # open worksheet, find today's action, and create unique list of players
+        try:
+            worksheet = getWorksheet(spreadsheet_key, json_keyfile)
+            first_row, last_row = getFirstRowLastRow(worksheet, current_date)
+            if first_row == "":
+                print("No games today! Pausing for 1000 seconds...")
+                time.sleep(1000)
+                continue
+            todays_cells = worksheet.range(first_row, 3, last_row, 10)
+            player_cells, player_names_unique = parsePlayersCells(todays_cells)
+            print("Today's players:", end=' ', flush=True)
+            print(player_names_unique)
+        except gspread.exceptions.APIError:
+            print("Google API overloaded, retrying in 10 seconds...")
+            time.sleep(10)
+            continue
+        except:
+            time.sleep(10)
+            continue
+
+        # Build stats dictionary from unique list of players
+        print("Retrieving player stats from NBA.com...")
+        stats_dict = buildStatsDict(player_names_unique, url_date, current_season)
+
+
+        update = False # only update the sheet if it has changed
+        for player_cell in player_cells:
+            player_update = False # Return if individual player stats have changed
+            player_name = cleanPlayerName(player_cell)
+            if stats_dict.get(player_name) != None: # skip players with empty stats
+                if stats_dict.get(player_name) == "Fix Name!":
+                    player_cell.value = str(player_cell.value) + "-FIX!!!"
+                    update = True
+                else:
+                    player_stats = stats_dict.get(player_name)
+                    todays_cells, update, player_update = updatePlayerStatsLocal(todays_cells, 
+                                                                                 player_cell, 
+                                                                                 player_stats, 
+                                                                                 update, 
+                                                                                 player_update)
+            if player_update == True:
+                print("Updated " + player_name + "\'s stats")
+            elif player_update == False:
+                print(player_name + "\'s stats have not changed")
+                    
+        if update == True:
+            while True:
+                try: 
+                    print("Pushing changes to google sheet...")
+                    worksheet.update_cells(todays_cells, 'USER_ENTERED')
+                    break
+                except gspread.exceptions.APIError:
+                    print("Google API overloaded, adding a 10 second delay...")
+                    time.sleep(10)
+                    continue
+        else:
+            print("No update necessary, pausing for 30 seconds...")
+            time.sleep(30)
+                
+        continue # restart entire loop
 
 

+ 0 - 3
requirements.txt

@@ -1,8 +1,5 @@
 gspread
 oauth2client
 datetime
-timeout-decorator
 requests
-time
-datetime
 git+git://github.com/swar/nba_api.git