Wondering if I can get a review of the following script.
I used to be a Python dev back when 2.7 was the norm and haven't really touched Python3, so interested to see where some new features might tidy things up. And obviously any improvements / direction on general style.
The script consumes an API that provides data that I take and format into an Excel spreadsheet. Eventually, it should live in a Lambda on AWS to be run periodically.
import os
import json
import requests
import xlsxwriter
from datetime import datetime
from collections import OrderedDict
from xlsxwriter.utility import xl_col_to_name
ACCESS_TOKEN = ''
WORKBOOK = ''
def create_daysheet():
worksheet = create_worksheet()
races = get_races_today()
write_meetings_to_sheet(worksheet=worksheet, races=races)
favourites = write_all_races_to_sheet(worksheet=worksheet, races=races)
write_fav_label_column(
row=0,
column=28,
worksheet=worksheet,
number_of_favourites=len(favourites)
)
write_races_list_to_sheet(
row=0,
column=29,
worksheet=worksheet,
races=races
)
write_protect_message(worksheet=worksheet)
write_race_percentages(
worksheet=worksheet,
number_of_favourites=len(favourites)
)
WORKBOOK.close()
def create_workbook():
today = datetime.today()
return xlsxwriter.Workbook(
'day-sheet-%s.xlsx' % today.strftime('%d-%m-%y')
)
def create_worksheet():
worksheet = WORKBOOK.add_worksheet()
worksheet.protect('123')
locked_format = get_locked_format()
worksheet.set_column('A:XDF', None, locked_format)
worksheet.set_default_row(12.6)
worksheet.set_column('A:A', 4.11)
worksheet.set_column('AA:AA', 3.11)
worksheet.set_column('AB:AB', 5.56)
cell_format = get_spacer_format()
worksheet.set_column('AC:AC', 0.63, cell_format)
worksheet.set_column('AF:AF', 4.56)
worksheet.set_column('AG:AG', 14.11)
worksheet.set_column('AH:AJ', 6.56)
worksheet.set_column('B:K', 2.56)
worksheet.set_column('L:L', 3.11)
worksheet.set_column('P:P', 4.11)
worksheet.set_column('Q:AA', 2.56)
worksheet.set_column('M:M', 5.22)
worksheet.set_column('N:N', 5.33)
worksheet.set_column('O:O', 1.67)
return worksheet
def get_spacer_format():
cell_format = WORKBOOK.add_format()
cell_format.set_bg_color('#000000')
return cell_format
def get_locked_format():
locked_format = WORKBOOK.add_format()
locked_format.set_locked(True)
return locked_format
def get_day_of_week_number():
return int(datetime.today().strftime('%w')) + 1
def get_week_number():
return int(datetime.today().strftime('%U')) + 1
def get_races_today():
day = get_day_of_week_number()
week = get_week_number()
year = datetime.today().year
url = ('xxx'
'xxx/{year}-{week}-{day}'
.format(
**{'day': day, 'week': week, 'year': year}
))
headers = {
'x-api-key': 'xxx',
'content-type': 'application/json; charset=UTF-8',
'referer': 'xxx',
'x-betfair-token': 'xxx',
'authorization': ACCESS_TOKEN
}
response = requests.get(url, headers=headers)
return response.json()
def get_racing_data(track_names):
url = 'xx'
headers = {
'x-api-key': 'xxx',
'content-type': 'application/json; charset=UTF-8',
'referer': 'xxx',
'authorization': ACCESS_TOKEN
}
day = get_day_of_week_number()
week = get_week_number()
data = {
"bz02_ip_gt": 0,
"bz04_ip_lt": 1002,
"bz06_sp_gt": 1,
"bz08_sp_lt": 1002,
"bz10_wk_from": week,
"bz12_wk_to": week,
"bz14_ran_from": 1,
"bz16_ran_to": 50,
"bz18_distance": "",
"bz20_ran": 0,
"bz22_race_type": "",
"bz24_fav": 0,
"bz26_days_of_week": "%s" % day,
"bz28_track": ', '.join(track_names),
"bz30_ire_uk": "",
"bz32_fav_sp1": 0,
"bz33_fav_sp2": 0,
"bz35_fav2_sp1": 0,
"bz36_fav2_sp2": 0,
"bz40_time_only1": 1.25,
"bz41_time_only2": 1.958333,
"bz43_fav_h": 0,
"bz72_loser_winner": 0,
"bz74_day": 0,
"bz76_month": 0,
"bz79_sp_gt": 0,
"bz81_sp_lt": 0,
"bz83_jmp_flat": 0,
"years": "2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018",
"bz38_hide_days": 0,
"bz69_raceno": 0,
"win_streak": 0,
"bz65_ire_plus": 0,
"bz49_racetype_2": "",
"bz47_dis_2": ""
}
raw_response = requests.post(
url,
data=json.dumps(data).replace(' ', ''),
headers=headers
)
return raw_response.json()
def split_races(races):
track_names = list(
set(
[
race['G_track']
for race in races
]
)
)
return {
track_name: [
race['N_time']
for race in races
if race['G_track'] == track_name
]
for track_name in track_names
}
def write_all_races_to_sheet(worksheet, races):
races_split = split_races(races=races)
track_names = races_split.keys()
racing_data = get_racing_data(track_names=track_names)
favourites = get_relevant_favourites(
favourites=racing_data['yrs']['Fav']
)
write_meeting_to_sheet(
worksheet=worksheet,
favourites=favourites,
row=0,
start_column=16
)
set_this_year_all_formulas(
row=2,
worksheet=worksheet,
number_of_favourites=len(favourites)
)
return favourites
def set_this_year_all_formulas(row, worksheet, number_of_favourites):
winner_format = get_winner_format()
for race_number in range(0, number_of_favourites):
target_cell = 'AA{row}'.format(
**{
'row': row + race_number
}
)
formula = 'COUNTIF(O:O,"{favourite_number}")'.format(
**{
'start_row': row,
'end_row': row + number_of_favourites,
'favourite_number': race_number + 1
}
)
worksheet.write_formula(target_cell, formula, winner_format)
def write_meetings_to_sheet(worksheet, races):
races_split = split_races(races=races)
row = 0
for track_name, times in races_split.items():
racing_data = get_racing_data(track_names=[track_name])
favourites = get_relevant_favourites(
favourites=racing_data['yrs']['Fav']
)
if not bool(favourites):
continue
write_track_and_time_to_sheet(
row=row,
worksheet=worksheet,
track_name=track_name,
times=times
)
write_meeting_to_sheet(
worksheet=worksheet,
favourites=favourites,
row=row,
start_column=1
)
set_this_year_races_formula(
row=row + 2,
worksheet=worksheet,
number_of_favourites=len(favourites),
number_of_races=len(times)
)
row += len(favourites) + 4
def set_this_year_races_formula(row, worksheet, number_of_favourites, number_of_races):
winner_format = get_winner_format()
for favourite_number in range(0, number_of_favourites):
target_cell = 'L{row}'.format(
**{
'row': row + favourite_number
}
)
formula = 'COUNTIF(O{start_row}:O{end_row},"{favourite_number}")'.format(
**{
'start_row': row,
'end_row': row + number_of_races,
'favourite_number': favourite_number + 1
}
)
worksheet.write_formula(target_cell, formula, winner_format)
def get_winner_format():
winner_format = create_base_format()
winner_format.set_align('center')
winner_format.set_align('vcenter')
winner_format.set_border(1)
winner_format.set_border_color('#a6a6a6')
return winner_format
def write_meeting_to_sheet(worksheet, favourites, row, start_column):
write_race_headers(
row=row,
column=start_column,
worksheet=worksheet,
number_of_favourites=len(favourites.keys())
)
row += 1
winner_format = get_winner_format()
for favourite, years in favourites.items():
column = start_column
del years['all']
for year, winners in years.items():
if winners != 0:
worksheet.write(row, column, winners, winner_format)
else:
worksheet.write(row, column, '', winner_format)
column += 1
worksheet.write(row, column, 0, winner_format)
row += 1
set_race_winners_conditional_format(
row=row,
start_column=start_column,
number_of_favourites=len(favourites.keys()),
worksheet=worksheet
)
write_totals_line(
row=row,
start_column=start_column,
worksheet=worksheet,
number_of_favourites=len(favourites.keys())
)
def get_time_format():
time_format = create_base_format()
time_format.set_font_size(9)
time_format.set_num_format('@')
time_format.set_border(1)
time_format.set_border_color('#000000')
time_format.set_align('right')
return time_format
def get_track_name_format():
track_name_format = create_base_format()
track_name_format.set_border(1)
track_name_format.set_border_color('#000000')
track_name_format.set_font_size(9)
return track_name_format
def write_track_and_time_to_sheet(row, worksheet, track_name, times):
column = 12
set_winner_conditional_format(
format_range='O1:O100',
worksheet=worksheet
)
time_format = get_time_format()
track_name_format = get_track_name_format()
for time in times:
row += 1
worksheet.write(row, column, time, time_format)
worksheet.write(row, column + 1, track_name, track_name_format)
set_race_time_forumula(row=row + 1, column=column + 2, worksheet=worksheet)
def set_race_time_forumula(row, column, worksheet):
track_name_format = get_track_name_format()
start_column = xl_col_to_name(column)
target_cell = '{column}{row}'.format(
**{
'column': start_column,
'row': row
}
)
formula = ('=IF(LEN(VLOOKUP({start_column}{start_row},AD:AF,3,FALSE))=0,"",'
'VLOOKUP({start_column}{start_row},AD:AF,3,FALSE))').format(
**{
'start_column': xl_col_to_name(column - 2),
'start_row': row
}
)
worksheet.write_formula(target_cell, formula, track_name_format)
def set_winner_conditional_format(format_range, worksheet):
fav_format = get_fav_format()
outsider_format = get_outsider_format()
blank_format = get_blank_format()
worksheet.conditional_format(
format_range,
{
'type': 'blanks',
'format': blank_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': '<=',
'value': 2,
'format': fav_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': '>=',
'value': 3,
'format': outsider_format,
'stop_if_true': True
}
)
def get_fav_format():
fav_format = create_base_format()
fav_format.set_pattern(1)
fav_format.set_align('center')
fav_format.set_align('vcenter')
fav_format.set_bg_color('#FFFF00')
return fav_format
def get_blank_format():
blank_format = create_base_format()
blank_format.set_align('center')
blank_format.set_align('vcenter')
return blank_format
def get_outsider_format():
outsider_format = create_base_format()
outsider_format.set_pattern(1)
outsider_format.set_align('center')
outsider_format.set_align('vcenter')
outsider_format.set_font_color('#FFFFFF')
outsider_format.set_bg_color('#203764')
return outsider_format
def get_danger_format():
danger_format = create_base_format()
danger_format.set_pattern(1)
danger_format.set_align('center')
danger_format.set_align('vcenter')
danger_format.set_font_color('#9c0000')
danger_format.set_bg_color('#ffc7ce')
return danger_format
def set_race_winners_conditional_format(row, start_column, number_of_favourites, worksheet):
fav_format = get_fav_format()
outsider_format = get_outsider_format()
fav_format_range = '{start_column}{start_row}:{end_column}{end_row}'.format(
**{
'start_column': xl_col_to_name(start_column),
'start_row': row - number_of_favourites + 1,
'end_column': xl_col_to_name(start_column + 10),
'end_row': row - number_of_favourites + 2
}
)
outsider_format_range = '{start_column}{start_row}:{end_column}{end_row}'.format(
**{
'start_column': xl_col_to_name(start_column),
'start_row': row - number_of_favourites + 3,
'end_column': xl_col_to_name(start_column + 10),
'end_row': row
}
)
set_fav_conditional_format(
format_range=fav_format_range,
worksheet=worksheet,
cell_format=fav_format
)
set_outsider_conditional_format(
format_range=outsider_format_range,
worksheet=worksheet,
cell_format=outsider_format
)
def set_fav_conditional_format(format_range, worksheet, cell_format):
blank_format = get_blank_format()
danger_format = get_danger_format()
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': '>=',
'value': 1,
'format': cell_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'blanks',
'format': blank_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': 'equal to',
'value': 0,
'format': danger_format,
'stop_if_true': True
}
)
def set_outsider_conditional_format(format_range, worksheet, cell_format):
blank_format = get_blank_format()
danger_format = get_danger_format()
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': '>=',
'value': 1,
'format': cell_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'blanks',
'format': blank_format,
'stop_if_true': True
}
)
worksheet.conditional_format(
format_range,
{
'type': 'cell',
'criteria': 'equal to',
'value': 0,
'format': danger_format,
'stop_if_true': True
}
)
def get_total_format():
total_format = create_base_format()
total_format.set_pattern(1)
total_format.set_align('center')
total_format.set_align('vcenter')
total_format.set_bg_color('#5E943C')
total_format.set_font_color('#FFFFFF')
return total_format
def write_totals_line(row, start_column, worksheet, number_of_favourites):
for column_number in range(start_column, start_column + 11):
column = xl_col_to_name(column_number)
target_cell = '{column}{row}'.format(
**{
'column': column,
'row': row + 1
}
)
formula = '=SUM({column}{row_start}:{column}{row_end})'.format(
**{
'column': column,
'row_start': row - number_of_favourites + 1,
'row_end': row
}
)
total_format = get_total_format()
worksheet.write_formula(target_cell, formula, total_format)
def get_relevant_favourites(favourites):
favourites = OrderedDict(favourites)
to_delete = []
del favourites['total']
for favourite, years in reversed(favourites.items()):
if favourites_not_empty(years=years):
break
to_delete.append(favourite)
for favourite in to_delete:
del favourites[favourite]
return favourites
def write_race_headers(row, column, worksheet, number_of_favourites):
cell_format = get_race_header_format()
write_column_headers(
row=row,
column=column,
worksheet=worksheet,
number_of_favourites=number_of_favourites,
cell_format=cell_format
)
worksheet.write(row, column - 1, 'Fav No', cell_format)
write_row_headers(
row=row,
column=column,
worksheet=worksheet,
cell_format=cell_format
)
def write_row_headers(row, column, worksheet, cell_format):
for year in range(2009, 2020):
if year != 2019:
worksheet.write(row, column, str(year)[-2:], cell_format)
else:
worksheet.write(row, column, year, cell_format)
column += 1
def write_column_headers(row, column, worksheet, number_of_favourites, cell_format):
special_cases = {
1: 'Fav',
2: '2nd',
3: '3rd',
21: '21st',
22: '22nd',
23: '23rd'
}
for favourite in range(1, number_of_favourites + 1):
row += 1
if favourite in special_cases:
worksheet.write(row, column - 1, special_cases[favourite], cell_format)
else:
worksheet.write(row, column - 1, '%sth' % favourite, cell_format)
def write_fav_label_column(row, column, worksheet, number_of_favourites):
write_column_headers(
row=row,
column=column,
worksheet=worksheet,
number_of_favourites=number_of_favourites,
cell_format=get_winner_format()
)
def favourites_not_empty(years):
for year, winners in years.items():
if winners > 0:
return True
return False
def get_race_header_format():
header_format = create_base_format()
header_format.set_bold()
header_format.set_pattern(1)
header_format.set_align('center')
header_format.set_align('vcenter')
header_format.set_bg_color('#D9D9D9')
header_format.set_font_color('#002060')
header_format.set_border(1)
header_format.set_border_color('#a6a6a6')
header_format.set_num_format('@')
return header_format
def create_base_format():
workbook_format = WORKBOOK.add_format()
workbook_format.set_font_name('Calibri')
workbook_format.set_font_size(8)
return workbook_format
def write_races_list_headers(row, column, worksheet):
cell_format = get_race_header_format()
cell_format.set_locked(False)
worksheet.write(row, column, 'Time', cell_format)
worksheet.write(row, column + 1, 'Track', cell_format)
worksheet.write(row, column + 2, 'Winner', cell_format)
worksheet.write(row, column + 3, 'Winner name', cell_format)
def write_races_list_to_sheet(row, column, worksheet, races):
write_races_list_headers(row=row, column=column, worksheet=worksheet)
cell_format = get_track_name_format()
cell_format.set_locked(False)
time_format = get_time_format()
time_format.set_locked(False)
for index, race in enumerate(races):
worksheet.write(row + index + 1, column, race['N_time'], time_format)
worksheet.write(row + index + 1, column + 1, race['G_track'], cell_format)
if 'Winner' in race:
winner = race['Winner']
else:
winner = ''
if 'WinnerName' in race:
winner_name = race['WinnerName']
else:
winner_name = ''
worksheet.write(row + index + 1, column + 2, winner, cell_format)
worksheet.write(row + index + 1, column + 3, winner_name, cell_format)
start_column = xl_col_to_name(column + 2)
start_row = row + 2
end_row = row + len(races) + 1
format_range = '{start_column}{start_row}:{end_column}{end_row}'.format(
**{
'start_column': start_column,
'start_row': start_row,
'end_column': start_column,
'end_row': end_row
}
)
set_winner_conditional_format(format_range=format_range, worksheet=worksheet)
def write_protect_message(worksheet):
worksheet.write(0, 33, 'Password to unlock the sheet is 123')
worksheet.write(2, 33, 'Only reason it is locked is to protect the formulas')
def write_race_percentages(worksheet, number_of_favourites):
start_row = 4
start_target_row = 2
for favourite_number in range(0, number_of_favourites):
worksheet.write(start_row + favourite_number, 33, favourite_number + 1)
set_percentage_win_count_formula(
start_row=start_row,
favourite_number=favourite_number,
worksheet=worksheet,
start_target_row=start_target_row
)
set_percentage_win_formula(
start_row=start_row,
favourite_number=favourite_number,
worksheet=worksheet,
number_of_favourites=number_of_favourites
)
set_percentage_win_sum_formula(
start_row=start_row,
worksheet=worksheet,
number_of_favourites=number_of_favourites
)
def set_percentage_win_formula(start_row, favourite_number, worksheet, number_of_favourites):
target_cell = 'AJ{row}'.format(
**{
'row': start_row + favourite_number + 1
}
)
formula = '=IF($AI{total_row}=0,0.0,SUM(AI{row}/AI{total_row}))'.format(
**{
'row': start_row + favourite_number + 1,
'total_row': start_row + number_of_favourites + 1
}
)
cell_format = create_base_format()
cell_format.set_num_format('0.00%')
worksheet.write_formula(target_cell, formula, cell_format)
def set_percentage_win_sum_formula(start_row, worksheet, number_of_favourites):
target_cell = 'AI{row}'.format(
**{
'row': start_row + number_of_favourites + 1
}
)
formula = '=SUM(AI{start_row}:AI{end_row})'.format(
**{
'start_row': start_row + 1,
'end_row': start_row + number_of_favourites - 1,
}
)
cell_format = create_base_format()
worksheet.write_formula(target_cell, formula, cell_format)
def set_percentage_win_count_formula(start_row, favourite_number, worksheet, start_target_row):
target_cell = 'AI{row}'.format(
**{
'row': start_row + favourite_number + 1
}
)
formula = '=AA{row}'.format(
**{
'row': start_target_row + favourite_number,
}
)
cell_format = create_base_format()
worksheet.write_formula(target_cell, formula, cell_format)
def login():
url = 'xxx'
headers = {
'x-api-key': 'xxx',
'content-type': 'application/json; charset=UTF-8',
'referer': 'xxx'
}
data = '{"user":"xxx","pass":"%s"}' % os.environ.get("RSA_PASSWORD")
raw_response = requests.post(url, data=data, headers=headers)
response = raw_response.json()
return response['accessToken']
if __name__ == '__main__':
ACCESS_TOKEN = login()
WORKBOOK = create_workbook()
create_daysheet()