def test_initialized_other_thread(self): self.fixtures = None pugsql.get_modules().clear() def init(): self.fixtures = pugsql.module('tests/sql/fixtures') self.fixtures.connect('sqlite:///./tests/data/fixtures.sqlite3') t = threading.Thread(target=init) t.start() t.join() self.assertEqual({ 'username': '******', 'user_id': 1 }, self.fixtures.user_for_id(user_id=1))
def setUp(self): pugsql.get_modules().clear() self.fixtures = pugsql.module('tests/sql/fixtures') self.fixtures.connect('sqlite:///./tests/data/fixtures.sqlite3')
def game_info(self, game_id: int): """ Main function for transforming the game summary and logs. Also outputs to Database. :param game_id: Integer for the game ID, used for identification and for urls. """ # Sends slack notification that job has begun; creates url Strings slack_message(f'Loading game ID {game_id}', 'scheduled-jobs') results_url = f'https://en.boardgamearena.com/#!table?table={game_id}' replay_url = f'https://en.boardgamearena.com/#!gamereview?table={game_id}' # Return and write locally the results data. summary_results = self.game_results(results_url) pickle.dump(summary_results, open('data/results.pkl', 'wb')) # Return and write locally the log data. logs = self.game_logs(replay_url) pickle.dump(logs, open('data/logs.pkl', 'wb')) # Assign player order by finding logs where the first player of each round switches player_order = list( set([ x[0:x.find(' is')] for x in logs if 'is now first player' in x ][0:4])) # For each log item, assign the player ID. player_nums = [] for x in logs: # Abandoned games are discarded. if 'chose to abandon' in x.lower(): self.game_ids.remove(game_id) slack_message('game abandoned', 'scheduled-jobs') return # These log items do not have any game impact and/or are not specific to a player elif 'end of the game' in x.lower(): player_nums.append(-1) elif 'end of game' in x.lower(): player_nums.append(-1) elif 'rematch' in x.lower(): player_nums.append(-1) elif 'colors of' in x.lower(): player_nums.append(-1) else: if 'out of time' in x.lower(): x = x[0:x.find('out of time') + 11] for i in range(len(player_order)): if x.find(player_order[i]) >= 0: player_nums.append(i) # Assigns player index/number in place of name in the logs. for player in player_order: logs = [x.replace(player, 'player') for x in logs] # For each log, replaces numbers with the character i, # and creates a separate field in the table structure to capture the value; # This normalizes player actions in the log table. values = [int((re.findall('\d+', x) or [-1])[0]) for x in logs] logs = [re.sub(r'\d', 'i', x) for x in logs] log_df = pd.DataFrame({ 'player_number': player_nums, 'value': values, 'action_name': logs, }) # Sets flag for a new turn/round; and assigns a turn/round number using that flag. log_df.loc[log_df['action_name'] == 'player is now first player', 'new_turn'] = 1 log_df['turn_number'] = log_df['new_turn'].fillna(0).cumsum() # Sets move number as an index starting at 1. log_df['move_number'] = log_df.index + 1 log_df['game_id'] = game_id log_df = log_df.drop('new_turn', axis=1) # Creates empty lists of the appropriate length for missing data. for key in summary_results.keys(): if len(summary_results[key]) == 0: summary_results[key] = [None] * len( summary_results['Player Names']) if ((len(summary_results[key]) == 2 * len(summary_results['Player Names']) and key == 'winpoints')): summary_results[key] = [ x.strip() for x in summary_results[key] if len(x) > 0 ] # Converts summary results into a DataFrame and does some string cleanup. summary_df = pd.DataFrame(summary_results) summary_df.columns = summary_df.columns.str.replace( "'", "").str.lower().str.replace(' ', '_') summary_df['game_id'] = game_id summary_df['player_idx'] = [ player_order.index(x) for x in summary_results['Player Names'] ] if (log_df.isnull().values.any()) or ( summary_df.isnull().values.any()): slack_message(f'Missing data found in tables:\n{summary_df}', 'job-errors') return # Writes tables to the database. pugsql.get_modules().clear() queries = pugsql.module('sql/') queries.connect(engine_builder(engine=False)) log_row_ct = queries.insert_logs(log_df.to_dict(orient='records')) summary_row_ct = queries.insert_summary( summary_df.to_dict(orient='records')) # Removes completed game ID from the list and writes local list of recent game IDs. self.game_ids.remove(game_id) self.write_new_game_ids() slack_message( f'Loaded game ID {game_id}' f'\n{summary_row_ct} rows added to summary' f'\n{log_row_ct} rows added to logs', 'scheduled-jobs')